Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add virtual-threads support in Quarkus #24942

Merged
merged 1 commit into from May 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
Expand Up @@ -212,6 +212,8 @@ public class DevMojo extends AbstractMojo {
@Parameter(defaultValue = "${debug}")
private String debug;

@Parameter(defaultValue = "${open-lang-package}")
private boolean openJavaLang;
/**
* Whether or not the JVM launch, in debug mode, should be suspended. This parameter is only
* relevant when the JVM is launched in {@link #debug debug mode}. This parameter supports the
Expand Down Expand Up @@ -956,6 +958,11 @@ private QuarkusDevModeLauncher newLauncher() throws Exception {
builder.jvmArgs("-Dio.quarkus.force-color-support=true");
}

if (openJavaLang) {
builder.jvmArgs("--add-opens");
builder.jvmArgs("java.base/java.lang=ALL-UNNAMED");
}

builder.projectDir(project.getFile().getParentFile());
builder.buildSystemProperties((Map) project.getProperties());

Expand Down
52 changes: 52 additions & 0 deletions extensions/netty-loom-adaptor/deployment/pom.xml
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-netty-loom-adaptor-parent</artifactId>
<version>999-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>quarkus-netty-loom-adaptor-deployment</artifactId>
<name>Quarkus - Netty Loom Adaptor - Deployment</name>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-netty-loom-adaptor</artifactId>
<version>999-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-netty-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core-deployment</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions extensions/netty-loom-adaptor/pom.xml
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<artifactId>quarkus-extensions-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>quarkus-netty-loom-adaptor-parent</artifactId>
<name>Quarkus - Netty Loom Adaptor</name>
<packaging>pom</packaging>

<modules>
<module>runtime</module>
<module>deployment</module>
</modules>



</project>
61 changes: 61 additions & 0 deletions extensions/netty-loom-adaptor/runtime/pom.xml
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-netty-loom-adaptor-parent</artifactId>
<version>999-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>quarkus-netty-loom-adaptor</artifactId>
<name>Quarkus - Netty Loom Adaptor - Runtime</name>
<description>Modifies some Netty classes to make it work with loom</description>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>commons-logging-jboss-logging</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-netty</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-bootstrap-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
3 changes: 3 additions & 0 deletions extensions/pom.xml
Expand Up @@ -14,6 +14,8 @@
<name>Quarkus - Extensions - Parent pom</name>
<packaging>pom</packaging>
<modules>
<!-- Netty loom adaptor-->
<module>netty-loom-adaptor</module>
<!-- Plumbing -->
<module>arc</module>
<module>scheduler</module>
Expand Down Expand Up @@ -193,6 +195,7 @@
<module>grpc-common</module>

<module>awt</module>

</modules>

<build>
Expand Down
Expand Up @@ -15,6 +15,7 @@
import io.quarkus.vertx.web.RouteFilter;
import io.quarkus.vertx.web.RoutingExchange;
import io.smallrye.common.annotation.Blocking;
import io.smallrye.common.annotation.RunOnVirtualThread;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import io.vertx.core.buffer.Buffer;
Expand Down Expand Up @@ -51,6 +52,7 @@ final class DotNames {
static final DotName EXCEPTION = DotName.createSimple(Exception.class.getName());
static final DotName THROWABLE = DotName.createSimple(Throwable.class.getName());
static final DotName BLOCKING = DotName.createSimple(Blocking.class.getName());
static final DotName RUN_ON_VIRTUAL_THREAD = DotName.createSimple(RunOnVirtualThread.class.getName());
static final DotName COMPLETION_STAGE = DotName.createSimple(CompletionStage.class.getName());
static final DotName COMPRESSED = DotName.createSimple(Compressed.class.getName());
static final DotName UNCOMPRESSED = DotName.createSimple(Uncompressed.class.getName());
Expand Down
Expand Up @@ -3,14 +3,18 @@
import static io.quarkus.resteasy.reactive.server.runtime.NotFoundExceptionMapper.classMappers;

import java.io.Closeable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

import javax.ws.rs.core.Application;

import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.common.core.SingletonBeanFactory;
import org.jboss.resteasy.reactive.common.model.ResourceContextResolver;
import org.jboss.resteasy.reactive.common.model.ResourceExceptionMapper;
Expand Down Expand Up @@ -55,12 +59,62 @@
@Recorder
public class ResteasyReactiveRecorder extends ResteasyReactiveCommonRecorder implements EndpointInvokerFactory {

static final Logger logger = Logger.getLogger("io.quarkus");

public static final Supplier<Executor> EXECUTOR_SUPPLIER = new Supplier<Executor>() {
@Override
public Executor get() {
return ExecutorRecorder.getCurrent();
}
};
public static final Supplier<Executor> VIRTUAL_EXECUTOR_SUPPLIER = new Supplier<Executor>() {
Executor current = null;

/**
* This method is used to specify a custom executor to dispatch virtual threads on carrier threads
* We need reflection for both ease of use (see {@link #get() Get} method) but also because we call methods
* of private classes from the java.lang package.
*
* It is used for testing purposes only for now
*/
private Executor setVirtualThreadCustomScheduler(Executor executor) throws ClassNotFoundException,
InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
var vtf = Class.forName("java.lang.ThreadBuilders").getDeclaredClasses()[0];
Constructor constructor = vtf.getDeclaredConstructors()[0];
constructor.setAccessible(true);
ThreadFactory tf = (ThreadFactory) constructor.newInstance(
new Object[] { executor, "quarkus-virtual-factory-", 0, 0,
null });

return (Executor) Executors.class.getMethod("newThreadPerTaskExecutor", ThreadFactory.class)
.invoke(this, tf);
}

/**
* This method uses reflection in order to allow developers to quickly test quarkus-loom without needing to
* change --release, --source, --target flags and to enable previews.
* Since we try to load the "Loom-preview" classes/methods at runtime, the application can even be compiled
* using java 11 and executed with a loom-compliant JDK.
*/
@Override
public Executor get() {
if (current == null) {
try {
current = (Executor) Executors.class.getMethod("newVirtualThreadPerTaskExecutor")
.invoke(this);
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
System.err.println(e);
//quite ugly but works
logger.warnf("You weren't able to create an executor that spawns virtual threads, the default" +
" blocking executor will be used, please check that your JDK is compatible with " +
"virtual threads");
//if for some reason a class/method can't be loaded or invoked we return the traditional EXECUTOR
current = EXECUTOR_SUPPLIER.get();
}
}
return current;
}
};

static volatile Deployment currentDeployment;

Expand Down Expand Up @@ -114,6 +168,7 @@ public ResteasyReactiveRequestContext createContext(Deployment deployment,
}

RuntimeDeploymentManager runtimeDeploymentManager = new RuntimeDeploymentManager(info, EXECUTOR_SUPPLIER,
VIRTUAL_EXECUTOR_SUPPLIER,
closeTaskHandler, contextFactory, new ArcThreadSetupAction(beanContainer.requestContext()),
vertxConfig.rootPath);
Deployment deployment = runtimeDeploymentManager.deploy();
Expand Down Expand Up @@ -164,6 +219,7 @@ public Application get() {
SingletonBeanFactory.setInstance(i.getClass().getName(), i);
}
applicationSupplier = new Supplier<Application>() {

@Override
public Application get() {
return application;
Expand Down
Expand Up @@ -6,5 +6,6 @@ public enum BlockingDefault {
*/
AUTOMATIC,
BLOCKING,
NON_BLOCKING
NON_BLOCKING,
RUN_ON_VIRTUAL_THREAD
}