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

ArC: introduce quarkus.arc.optimize-contexts=auto #38121

Merged
merged 1 commit into from
Jan 10, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -224,13 +224,21 @@ public class ArcConfig {
public ArcContextPropagationConfig contextPropagation;

/**
* If set to {@code true}, the container should try to optimize the contexts for some of the scopes.
* If set to {@code true}, the container should try to optimize the contexts for some of the scopes. If set to {@code auto}
* then optimize the contexts if there's less than 1000 beans in the application. If set to {@code false} do not optimize
* the contexts.
* <p>
* Typically, some implementation parts of the context for {@link jakarta.enterprise.context.ApplicationScoped} could be
* pregenerated during build.
*/
@ConfigItem(defaultValue = "true", generateDocumentation = false)
public boolean optimizeContexts;
@ConfigItem(defaultValue = "auto", generateDocumentation = false)
public OptimizeContexts optimizeContexts;

public enum OptimizeContexts {
TRUE,
FALSE,
AUTO
}

public final boolean isRemoveUnusedBeansFieldValid() {
return ALLOWED_REMOVE_UNUSED_BEANS_VALUES.contains(removeUnusedBeans.toLowerCase());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,23 @@ public Integer compute(AnnotationTarget target, Collection<StereotypeInfo> stere
}

builder.setBuildCompatibleExtensions(buildCompatibleExtensions.entrypoint);
builder.setOptimizeContexts(arcConfig.optimizeContexts);
builder.setOptimizeContexts(new Predicate<BeanDeployment>() {
@Override
public boolean test(BeanDeployment deployment) {
switch (arcConfig.optimizeContexts) {
case TRUE:
return true;
case FALSE:
return false;
case AUTO:
// Optimize the context if there is less than 1000 beans in the app
// Note that removed beans are excluded
return deployment.getBeans().size() < 1000;
default:
throw new IllegalArgumentException("Unexpected value: " + arcConfig.optimizeContexts);
}
}
});

BeanProcessor beanProcessor = builder.build();
ContextRegistrar.RegistrationContext context = beanProcessor.registerCustomContexts();
Expand Down Expand Up @@ -598,7 +614,7 @@ public ArcContainerBuildItem initializeContainer(ArcConfig config, ArcRecorder r
throws Exception {
ArcContainer container = recorder.initContainer(shutdown,
currentContextFactory.isPresent() ? currentContextFactory.get().getFactory() : null,
config.strictCompatibility, config.optimizeContexts);
config.strictCompatibility);
return new ArcContainerBuildItem(container);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.quarkus.arc.test.context.optimized;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.ServiceLoader;

import jakarta.inject.Inject;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.arc.ComponentsProvider;
import io.quarkus.test.QuarkusUnitTest;

public class OptimizeContextsAutoTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot(root -> root
.addClasses(SimpleBean.class))
.overrideConfigKey("quarkus.arc.optimize-contexts", "auto");

@Inject
SimpleBean bean;

@Test
public void testContexts() {
assertTrue(bean.ping());
for (ComponentsProvider componentsProvider : ServiceLoader.load(ComponentsProvider.class)) {
// We have less than 1000 beans
assertFalse(componentsProvider.getComponents().getContextInstances().isEmpty());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.quarkus.arc.test.context.optimized;

import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.ServiceLoader;

import jakarta.inject.Inject;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.arc.ComponentsProvider;
import io.quarkus.test.QuarkusUnitTest;

public class OptimizeContextsDisabledTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot(root -> root
.addClasses(SimpleBean.class))
.overrideConfigKey("quarkus.arc.optimize-contexts", "false");

@Inject
SimpleBean bean;

@Test
public void testContexts() {
assertTrue(bean.ping());
for (ComponentsProvider componentsProvider : ServiceLoader.load(ComponentsProvider.class)) {
assertTrue(componentsProvider.getComponents().getContextInstances().isEmpty());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.quarkus.arc.test.context.optimized;

import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
class SimpleBean {

public boolean ping() {
return true;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,10 @@ public class ArcRecorder {
public static volatile Map<String, Function<SyntheticCreationalContext<?>, ?>> syntheticBeanProviders;

public ArcContainer initContainer(ShutdownContext shutdown, RuntimeValue<CurrentContextFactory> currentContextFactory,
boolean strictCompatibility, boolean optimizeContexts)
throws Exception {
boolean strictCompatibility) throws Exception {
ArcInitConfig.Builder builder = ArcInitConfig.builder();
builder.setCurrentContextFactory(currentContextFactory != null ? currentContextFactory.getValue() : null);
builder.setStrictCompatibility(strictCompatibility);
builder.setOptimizeContexts(optimizeContexts);
ArcContainer container = Arc.initialize(builder.build());
shutdown.addShutdownTask(new Runnable() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public static Builder builder() {
private final boolean generateSources;
private final boolean allowMocking;
private final boolean transformUnproxyableClasses;
private final boolean optimizeContexts;
private final Predicate<BeanDeployment> optimizeContexts;
private final List<Function<BeanInfo, Consumer<BytecodeCreator>>> suppressConditionGenerators;

// This predicate is used to filter annotations for InjectionPoint metadata
Expand Down Expand Up @@ -187,6 +187,7 @@ public List<Resource> generateResources(ReflectionRegistration reflectionRegistr

ReflectionRegistration refReg = reflectionRegistration != null ? reflectionRegistration : this.reflectionRegistration;
PrivateMembersCollector privateMembers = new PrivateMembersCollector();
boolean optimizeContextsValue = optimizeContexts != null ? optimizeContexts.test(beanDeployment) : false;

// These maps are precomputed and then used in the ComponentsProviderGenerator which is generated first
Map<BeanInfo, String> beanToGeneratedName = new HashMap<>();
Expand Down Expand Up @@ -240,7 +241,7 @@ public List<Resource> generateResources(ReflectionRegistration reflectionRegistr

ContextInstancesGenerator contextInstancesGenerator = new ContextInstancesGenerator(generateSources,
refReg, beanDeployment, scopeToGeneratedName);
if (optimizeContexts) {
if (optimizeContextsValue) {
contextInstancesGenerator.precomputeGeneratedName(BuiltinScope.APPLICATION.getName());
contextInstancesGenerator.precomputeGeneratedName(BuiltinScope.REQUEST.getName());
}
Expand Down Expand Up @@ -364,7 +365,7 @@ public Collection<Resource> call() throws Exception {
}));
}

if (optimizeContexts) {
if (optimizeContextsValue) {
// Generate _ContextInstances
primaryTasks.add(executor.submit(new Callable<Collection<Resource>>() {

Expand Down Expand Up @@ -450,7 +451,7 @@ public Collection<Resource> call() throws Exception {
observerToGeneratedName,
scopeToGeneratedName));

if (optimizeContexts) {
if (optimizeContextsValue) {
// Generate _ContextInstances
resources.addAll(contextInstancesGenerator.generate(BuiltinScope.APPLICATION.getName()));
resources.addAll(contextInstancesGenerator.generate(BuiltinScope.REQUEST.getName()));
Expand Down Expand Up @@ -564,7 +565,7 @@ public static class Builder {
boolean failOnInterceptedPrivateMethod;
boolean allowMocking;
boolean strictCompatibility;
boolean optimizeContexts;
Predicate<BeanDeployment> optimizeContexts;

AlternativePriorities alternativePriorities;
final List<Predicate<ClassInfo>> excludeTypes;
Expand Down Expand Up @@ -600,7 +601,6 @@ public Builder() {
failOnInterceptedPrivateMethod = false;
allowMocking = false;
strictCompatibility = false;
optimizeContexts = false;

excludeTypes = new ArrayList<>();

Expand Down Expand Up @@ -842,7 +842,21 @@ public Builder setStrictCompatibility(boolean strictCompatibility) {
* @return self
*/
public Builder setOptimizeContexts(boolean value) {
this.optimizeContexts = value;
return setOptimizeContexts(new Predicate<BeanDeployment>() {
@Override
public boolean test(BeanDeployment t) {
return value;
}
});
}

/**
*
* @param fun
* @return self
*/
public Builder setOptimizeContexts(Predicate<BeanDeployment> fun) {
this.optimizeContexts = fun;
return this;
}

Expand Down