Skip to content

Commit

Permalink
Merge pull request #8579 from mkouba/vertx-web-route-perf-fix
Browse files Browse the repository at this point in the history
Reactive routes - fix race condition in generated handlers
  • Loading branch information
stuartwdouglas authored Apr 16, 2020
2 parents 57fe4ce + 4297e2c commit aca4ceb
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import io.quarkus.arc.InjectableReferenceProvider;
import io.quarkus.arc.deployment.AnnotationsTransformerBuildItem;
import io.quarkus.arc.deployment.BeanArchiveIndexBuildItem;
import io.quarkus.arc.deployment.BeanContainerBuildItem;
import io.quarkus.arc.deployment.CustomScopeAnnotationsBuildItem;
import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
import io.quarkus.arc.deployment.UnremovableBeanBuildItem.BeanClassAnnotationExclusion;
Expand Down Expand Up @@ -130,6 +129,7 @@ class VertxWebProcessor {
private static final MethodDescriptor INJECTABLE_BEAN_DESTROY = MethodDescriptor.ofMethod(InjectableBean.class, "destroy",
void.class, Object.class,
CreationalContext.class);
static final MethodDescriptor OBJECT_CONSTRUCTOR = MethodDescriptor.ofConstructor(Object.class);

@BuildStep
FeatureBuildItem feature() {
Expand Down Expand Up @@ -328,12 +328,6 @@ void addAdditionalRoutes(
detectConflictingRoutes(matchers);
}

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void initRouteHandlers(VertxWebRecorder recorder, BeanContainerBuildItem container) {
recorder.initHandlers();
}

@BuildStep
AnnotationsTransformerBuildItem annotationTransformer(CustomScopeAnnotationsBuildItem scopes) {
return new AnnotationsTransformerBuildItem(new AnnotationsTransformer() {
Expand Down Expand Up @@ -418,34 +412,37 @@ private String generateHandler(BeanInfo bean, MethodInfo method, ClassOutput cla
.setModifiers(ACC_PRIVATE | ACC_FINAL);
}

implementInitialize(bean, invokerCreator, beanField, contextField, containerField);
implementConstructor(bean, invokerCreator, beanField, contextField, containerField);
implementInvoke(bean, method, invokerCreator, beanField, contextField, containerField);

invokerCreator.close();
return generatedName.replace('/', '.');
}

void implementInitialize(BeanInfo bean, ClassCreator invokerCreator, FieldCreator beanField, FieldCreator contextField,
void implementConstructor(BeanInfo bean, ClassCreator invokerCreator, FieldCreator beanField, FieldCreator contextField,
FieldCreator containerField) {
MethodCreator initialize = invokerCreator.getMethodCreator("initialize", void.class);
ResultHandle containerHandle = initialize
MethodCreator constructor = invokerCreator.getMethodCreator("<init>", void.class);
// Invoke super()
constructor.invokeSpecialMethod(OBJECT_CONSTRUCTOR, constructor.getThis());

ResultHandle containerHandle = constructor
.invokeStaticMethod(ARC_CONTAINER);
ResultHandle beanHandle = initialize.invokeInterfaceMethod(
ResultHandle beanHandle = constructor.invokeInterfaceMethod(
ARC_CONTAINER_BEAN,
containerHandle, initialize.load(bean.getIdentifier()));
initialize.writeInstanceField(beanField.getFieldDescriptor(), initialize.getThis(), beanHandle);
containerHandle, constructor.load(bean.getIdentifier()));
constructor.writeInstanceField(beanField.getFieldDescriptor(), constructor.getThis(), beanHandle);
if (contextField != null) {
initialize.writeInstanceField(contextField.getFieldDescriptor(), initialize.getThis(),
initialize.invokeInterfaceMethod(
constructor.writeInstanceField(contextField.getFieldDescriptor(), constructor.getThis(),
constructor.invokeInterfaceMethod(
ARC_CONTAINER_GET_ACTIVE_CONTEXT,
containerHandle, initialize
containerHandle, constructor
.invokeInterfaceMethod(
BEAN_GET_SCOPE,
beanHandle)));
} else {
initialize.writeInstanceField(containerField.getFieldDescriptor(), initialize.getThis(), containerHandle);
constructor.writeInstanceField(containerField.getFieldDescriptor(), constructor.getThis(), containerHandle);
}
initialize.returnValue(null);
constructor.returnValue(null);
}

void implementInvoke(BeanInfo bean, MethodInfo method, ClassCreator invokerCreator, FieldCreator beanField,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@
*/
public interface RouteHandler extends Handler<RoutingContext> {

/**
* Initialize the handler instance before it is put into service.
*/
void initialize();

/**
* Invokes the route method.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package io.quarkus.vertx.web.runtime;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

import io.quarkus.runtime.annotations.Recorder;
Expand All @@ -15,8 +13,6 @@
@Recorder
public class VertxWebRecorder {

static volatile List<RouteHandler> handlers = new ArrayList<>();

@SuppressWarnings("unchecked")
public Handler<RoutingContext> createHandler(String handlerClassName) {
try {
Expand All @@ -27,21 +23,13 @@ public Handler<RoutingContext> createHandler(String handlerClassName) {
Class<? extends Handler<RoutingContext>> handlerClazz = (Class<? extends Handler<RoutingContext>>) cl
.loadClass(handlerClassName);
RouteHandler handler = (RouteHandler) handlerClazz.getDeclaredConstructor().newInstance();
handlers.add(handler);
return handler;
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException
| InvocationTargetException e) {
throw new IllegalStateException("Unable to create route handler: " + handlerClassName, e);
}
}

public void initHandlers() {
for (RouteHandler routeHandler : handlers) {
routeHandler.initialize();
}
handlers.clear();
}

public Function<Router, io.vertx.ext.web.Route> createRouteFunction(RouteMatcher matcher,
Handler<RoutingContext> bodyHandler) {
return new Function<Router, io.vertx.ext.web.Route>() {
Expand Down Expand Up @@ -81,4 +69,4 @@ public io.vertx.ext.web.Route apply(Router router) {
};
}

}
}

0 comments on commit aca4ceb

Please sign in to comment.