Skip to content

Commit

Permalink
Reduce Config startup footprint
Browse files Browse the repository at this point in the history
  • Loading branch information
radcortez committed Dec 13, 2022
1 parent 6cb8ffa commit c692412
Show file tree
Hide file tree
Showing 6 changed files with 283 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -405,12 +405,11 @@ public static final class GenerateOperation implements AutoCloseable {
}

// additional config builders
ResultHandle staticConfigBuilderInstances = clinit.newInstance(AL_NEW);
ResultHandle configBuilders = clinit.newInstance(AL_NEW);
for (String configBuilder : staticConfigBuilders) {
ResultHandle staticConfigBuilderInstance = clinit.newInstance(MethodDescriptor.ofConstructor(configBuilder));
clinit.invokeVirtualMethod(AL_ADD, staticConfigBuilderInstances, staticConfigBuilderInstance);
clinit.invokeVirtualMethod(AL_ADD, configBuilders, clinit.load(configBuilder));
}
clinit.invokeStaticMethod(CU_CONFIG_BUILDER_LIST, buildTimeBuilder, staticConfigBuilderInstances);
clinit.invokeStaticMethod(CU_CONFIG_BUILDER_LIST, buildTimeBuilder, configBuilders);

clinitConfig = clinit.checkCast(clinit.invokeVirtualMethod(SRCB_BUILD, buildTimeBuilder),
SmallRyeConfig.class);
Expand Down Expand Up @@ -561,15 +560,12 @@ public void run() {
}

// add bootstrap config builders
ResultHandle bootstrapConfigBuilderInstances = readBootstrapConfig.newInstance(AL_NEW);
ResultHandle bootstrapConfigBuilders = readBootstrapConfig.newInstance(AL_NEW);
for (String configBuilder : staticConfigBuilders) {
ResultHandle staticConfigBuilderInstance = readBootstrapConfig
.newInstance(MethodDescriptor.ofConstructor(configBuilder));
readBootstrapConfig.invokeVirtualMethod(AL_ADD, bootstrapConfigBuilderInstances,
staticConfigBuilderInstance);
readBootstrapConfig.invokeVirtualMethod(AL_ADD, bootstrapConfigBuilders,
readBootstrapConfig.load(configBuilder));
}
readBootstrapConfig.invokeStaticMethod(CU_CONFIG_BUILDER_LIST, bootstrapBuilder,
bootstrapConfigBuilderInstances);
readBootstrapConfig.invokeStaticMethod(CU_CONFIG_BUILDER_LIST, bootstrapBuilder, bootstrapConfigBuilders);
}

// add in our custom sources
Expand Down Expand Up @@ -657,13 +653,11 @@ public void run() {
}

// additional config builders
ResultHandle runtimeConfigBuilderInstances = readConfig.newInstance(AL_NEW);
ResultHandle configBuilders = readConfig.newInstance(AL_NEW);
for (String configBuilder : runtimeConfigBuilders) {
ResultHandle runtimeConfigBuilderInstance = readConfig
.newInstance(MethodDescriptor.ofConstructor(configBuilder));
readConfig.invokeVirtualMethod(AL_ADD, runtimeConfigBuilderInstances, runtimeConfigBuilderInstance);
readConfig.invokeVirtualMethod(AL_ADD, configBuilders, readConfig.load(configBuilder));
}
readConfig.invokeStaticMethod(CU_CONFIG_BUILDER_LIST, runTimeBuilder, runtimeConfigBuilderInstances);
readConfig.invokeStaticMethod(CU_CONFIG_BUILDER_LIST, runTimeBuilder, configBuilders);

ResultHandle bootstrapConfig = null;
if (bootstrapConfigSetupNeeded()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
import static io.quarkus.deployment.configuration.ConfigMappingUtils.processExtensionConfigMapping;
import static io.quarkus.deployment.steps.ConfigBuildSteps.SERVICES_PREFIX;
import static io.quarkus.deployment.util.ServiceUtil.classNamesNamedIn;
import static io.quarkus.runtime.configuration.ConfigUtils.QUARKUS_BUILD_TIME_RUNTIME_PROPERTIES;
import static io.smallrye.config.ConfigMappings.ConfigClassWithPrefix.configClassWithPrefix;
import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_LOCATIONS;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.URI;
Expand All @@ -23,7 +21,6 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;

Expand All @@ -33,6 +30,7 @@
import org.eclipse.microprofile.config.ConfigValue;
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.eclipse.microprofile.config.spi.ConfigSourceProvider;
import org.objectweb.asm.Opcodes;

import io.quarkus.deployment.GeneratedClassGizmoAdaptor;
import io.quarkus.deployment.IsNormal;
Expand All @@ -47,7 +45,6 @@
import io.quarkus.deployment.builditem.ConfigurationBuildItem;
import io.quarkus.deployment.builditem.ConfigurationTypeBuildItem;
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
import io.quarkus.deployment.builditem.GeneratedResourceBuildItem;
import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem;
import io.quarkus.deployment.builditem.LaunchModeBuildItem;
import io.quarkus.deployment.builditem.LiveReloadBuildItem;
Expand All @@ -57,27 +54,39 @@
import io.quarkus.deployment.builditem.StaticInitConfigSourceFactoryBuildItem;
import io.quarkus.deployment.builditem.StaticInitConfigSourceProviderBuildItem;
import io.quarkus.deployment.builditem.SuppressNonRuntimeConfigChangedWarningBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.configuration.BuildTimeConfigurationReader;
import io.quarkus.deployment.configuration.RunTimeConfigurationGenerator;
import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
import io.quarkus.deployment.recording.RecorderContext;
import io.quarkus.gizmo.ClassCreator;
import io.quarkus.gizmo.ClassOutput;
import io.quarkus.gizmo.FieldDescriptor;
import io.quarkus.gizmo.MethodCreator;
import io.quarkus.gizmo.MethodDescriptor;
import io.quarkus.gizmo.ResultHandle;
import io.quarkus.runtime.LaunchMode;
import io.quarkus.runtime.annotations.StaticInitSafe;
import io.quarkus.runtime.configuration.ConfigBuilder;
import io.quarkus.runtime.configuration.ConfigDiagnostic;
import io.quarkus.runtime.configuration.ConfigRecorder;
import io.quarkus.runtime.configuration.ConfigUtils;
import io.quarkus.runtime.configuration.DefaultsConfigSource;
import io.quarkus.runtime.configuration.DisableableConfigSource;
import io.quarkus.runtime.configuration.QuarkusConfigValue;
import io.quarkus.runtime.configuration.RuntimeOverrideConfigSource;
import io.smallrye.config.ConfigMappings.ConfigClassWithPrefix;
import io.smallrye.config.ConfigSourceFactory;
import io.smallrye.config.PropertiesLocationConfigSourceFactory;
import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigBuilder;

public class ConfigGenerationBuildStep {
private static final MethodDescriptor CONFIG_BUILDER = MethodDescriptor.ofMethod(
ConfigBuilder.class, "configBuilder",
SmallRyeConfigBuilder.class, SmallRyeConfigBuilder.class);
private static final MethodDescriptor WITH_SOURCES = MethodDescriptor.ofMethod(
SmallRyeConfigBuilder.class, "withSources",
SmallRyeConfigBuilder.class, ConfigSource[].class);

@BuildStep
void staticInitSources(
Expand All @@ -91,43 +100,85 @@ void staticInitSources(
@BuildStep
void buildTimeRunTimeConfig(
ConfigurationBuildItem configItem,
BuildProducer<GeneratedResourceBuildItem> generatedResource,
BuildProducer<NativeImageResourceBuildItem> nativeImageResource) throws Exception {
BuildProducer<GeneratedClassBuildItem> generatedClass,
BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
BuildProducer<StaticInitConfigBuilderBuildItem> staticInitConfigBuilder,
BuildProducer<RunTimeConfigBuilderBuildItem> runTimeConfigBuilder) {

String className = "io.quarkus.runtime.generated.BuildTimeRunTimeFixedConfigSource";
generateDefaultsConfigSource(generatedClass, reflectiveClass, configItem.getReadResult().getBuildTimeRunTimeValues(),
className, "BuildTime RunTime Fixed", Integer.MAX_VALUE);

String builderClassName = className + "Builder";
try (ClassCreator classCreator = ClassCreator.builder()
.classOutput(new GeneratedClassGizmoAdaptor(generatedClass, true))
.className(builderClassName)
.interfaces(ConfigBuilder.class)
.setFinal(true)
.build()) {

MethodCreator method = classCreator.getMethodCreator(CONFIG_BUILDER);
ResultHandle configBuilder = method.getMethodParam(0);

ResultHandle buildTimeRunTimeConfigSource = method.newInstance(MethodDescriptor.ofConstructor(className));
ResultHandle disableableConfigSource = method.newInstance(
MethodDescriptor.ofConstructor(DisableableConfigSource.class, ConfigSource.class),
buildTimeRunTimeConfigSource);

Map<String, String> buildTimeRunTimeValues = configItem.getReadResult().getBuildTimeRunTimeValues();
Properties properties = new Properties();
for (Map.Entry<String, String> entry : buildTimeRunTimeValues.entrySet()) {
properties.setProperty(entry.getKey(), entry.getValue());
ResultHandle configSources = method.newArray(ConfigSource.class, 1);
method.writeArrayValue(configSources, 0, disableableConfigSource);

method.invokeVirtualMethod(WITH_SOURCES, configBuilder, configSources);

method.returnValue(configBuilder);
}

ByteArrayOutputStream out = new ByteArrayOutputStream();
properties.store(out, null);
generatedResource.produce(new GeneratedResourceBuildItem(QUARKUS_BUILD_TIME_RUNTIME_PROPERTIES, out.toByteArray()));
nativeImageResource.produce(new NativeImageResourceBuildItem(QUARKUS_BUILD_TIME_RUNTIME_PROPERTIES));
reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, false, builderClassName));
staticInitConfigBuilder.produce(new StaticInitConfigBuilderBuildItem(builderClassName));
runTimeConfigBuilder.produce(new RunTimeConfigBuilderBuildItem(builderClassName));
}

@BuildStep
void runtimeDefaultsConfig(
ConfigurationBuildItem configItem,
List<RunTimeConfigurationDefaultBuildItem> runTimeDefaults,
BuildProducer<GeneratedResourceBuildItem> generatedResource,
BuildProducer<NativeImageResourceBuildItem> nativeImageResource) throws IOException {
BuildProducer<GeneratedClassBuildItem> generatedClass,
BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
BuildProducer<StaticInitConfigBuilderBuildItem> staticInitConfigBuilder,
BuildProducer<RunTimeConfigBuilderBuildItem> runTimeConfigBuilder) {

Properties properties = new Properties();
Map<String, String> defaults = new HashMap<>();
for (RunTimeConfigurationDefaultBuildItem e : runTimeDefaults) {
properties.setProperty(e.getKey(), e.getValue());
defaults.put(e.getKey(), e.getValue());
}
defaults.putAll(configItem.getReadResult().getRunTimeDefaultValues());

String className = "io.quarkus.runtime.generated.RunTimeDefaultsConfigSource";
generateDefaultsConfigSource(generatedClass, reflectiveClass, defaults,
className, "RunTime Defaults", Integer.MIN_VALUE + 100);

Map<String, String> runTimeDefaultValues = configItem.getReadResult().getRunTimeDefaultValues();
for (Map.Entry<String, String> entry : runTimeDefaultValues.entrySet()) {
properties.setProperty(entry.getKey(), entry.getValue());
String builderClassName = className + "Builder";
try (ClassCreator classCreator = ClassCreator.builder()
.classOutput(new GeneratedClassGizmoAdaptor(generatedClass, true))
.className(builderClassName)
.interfaces(ConfigBuilder.class)
.setFinal(true)
.build()) {

MethodCreator method = classCreator.getMethodCreator(CONFIG_BUILDER);
ResultHandle configBuilder = method.getMethodParam(0);

ResultHandle configSources = method.newArray(ConfigSource.class, 1);
method.writeArrayValue(configSources, 0, method.newInstance(MethodDescriptor.ofConstructor(className)));

method.invokeVirtualMethod(WITH_SOURCES, configBuilder, configSources);

method.returnValue(configBuilder);
}

ByteArrayOutputStream out = new ByteArrayOutputStream();
properties.store(out, null);
generatedResource.produce(
new GeneratedResourceBuildItem(ConfigUtils.QUARKUS_RUNTIME_CONFIG_DEFAULTS_PROPERTIES, out.toByteArray()));
nativeImageResource.produce(new NativeImageResourceBuildItem(ConfigUtils.QUARKUS_RUNTIME_CONFIG_DEFAULTS_PROPERTIES));
reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, false, builderClassName));
staticInitConfigBuilder.produce(new StaticInitConfigBuilderBuildItem(builderClassName));
runTimeConfigBuilder.produce(new RunTimeConfigBuilderBuildItem(builderClassName));
}

@BuildStep
Expand Down Expand Up @@ -359,6 +410,46 @@ private String appendProfileToFilename(String path, String activeProfile) {
return String.format("%s-%s.%s", pathWithoutExtension, activeProfile, FilenameUtils.getExtension(path));
}

private static void generateDefaultsConfigSource(
BuildProducer<GeneratedClassBuildItem> generatedClass,
BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
Map<String, String> defaults,
String className,
String sourceName,
int sourceOrdinal) {

try (ClassCreator classCreator = ClassCreator.builder()
.classOutput(new GeneratedClassGizmoAdaptor(generatedClass, true))
.className(className)
.superClass(DefaultsConfigSource.class)
.setFinal(true)
.build()) {

FieldDescriptor properties = FieldDescriptor.of(classCreator.getClassName(), "properties", Map.class);
classCreator.getFieldCreator(properties).setModifiers(Opcodes.ACC_STATIC | Opcodes.ACC_FINAL);

MethodCreator clinit = classCreator.getMethodCreator("<clinit>", void.class);
clinit.setModifiers(Opcodes.ACC_STATIC);
clinit.writeStaticField(properties, clinit.newInstance(MethodDescriptor.ofConstructor(HashMap.class)));

ResultHandle map = clinit.readStaticField(properties);
MethodDescriptor put = MethodDescriptor.ofMethod(Map.class, "put", Object.class, Object.class, Object.class);
for (Map.Entry<String, String> entry : defaults.entrySet()) {
clinit.invokeInterfaceMethod(put, map, clinit.load(entry.getKey()), clinit.load(entry.getValue()));
}
clinit.returnVoid();

MethodCreator ctor = classCreator.getMethodCreator("<init>", void.class);
MethodDescriptor superCtor = MethodDescriptor.ofConstructor(DefaultsConfigSource.class, Map.class, String.class,
int.class);
ctor.invokeSpecialMethod(superCtor, ctor.getThis(), ctor.readStaticField(properties),
ctor.load(sourceName), ctor.load(sourceOrdinal));
ctor.returnVoid();
}

reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, false, className));
}

private static Set<String> discoverService(
Class<?> serviceClass,
BuildProducer<ReflectiveClassBuildItem> reflectiveClass) throws IOException {
Expand Down
Loading

0 comments on commit c692412

Please sign in to comment.