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

Split creation of the Set to match unknown properties to avoid MethodTooLargeException #44624

Merged
merged 1 commit into from
Nov 25, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public String getId() {
}

// ConfigMapping
ConfigClass mapping = readResult.getAllMappings().get(entry.getKey());
ConfigClass mapping = readResult.getAllMappingsByClass().get(entry.getKey());
if (mapping != null) {
mappingClasses.put(entry.getValue(), mapping);
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -628,9 +628,9 @@ ReadResult run() {
objectsByClass.put(mapping.getKlass(), config.getConfigMapping(mapping.getKlass(), mapping.getPrefix()));
}

Set<PropertyName> buildTimeNames = getMappingsNames(buildTimeMappings);
Set<PropertyName> buildTimeRunTimeNames = getMappingsNames(buildTimeRunTimeMappings);
Set<PropertyName> runTimeNames = getMappingsNames(runTimeMappings);
Set<PropertyName> buildTimeNames = mappingsToNames(buildTimeMappings).keySet();
Set<PropertyName> buildTimeRunTimeNames = mappingsToNames(buildTimeRunTimeMappings).keySet();
Set<PropertyName> runTimeNames = mappingsToNames(runTimeMappings).keySet();
for (String property : allProperties) {
PropertyName name = new PropertyName(property);
if (buildTimeNames.contains(name)) {
Expand Down Expand Up @@ -1222,12 +1222,32 @@ private static void getDefaults(
}
}

private static Set<PropertyName> getMappingsNames(final List<ConfigClass> configMappings) {
private static Map<PropertyName, String> mappingsToNames(final List<ConfigClass> configMappings) {
Set<String> names = new HashSet<>();
for (ConfigClass configMapping : configMappings) {
names.addAll(ConfigMappings.getProperties(configMapping).keySet());
}
return PropertiesUtil.toPropertyNames(names);
Map<PropertyName, String> propertyNames = new HashMap<>();
for (String name : names) {
PropertyName propertyName = new PropertyName(name);
if (propertyNames.containsKey(propertyName)) {
String existing = propertyNames.remove(propertyName);
if (existing.length() < name.length()) {
propertyNames.put(new PropertyName(existing), existing);
} else if (existing.length() > name.length()) {
propertyNames.put(propertyName, name);
} else {
if (existing.indexOf('*') <= name.indexOf('*')) {
propertyNames.put(new PropertyName(existing), existing);
} else {
propertyNames.put(propertyName, name);
}
}
} else {
propertyNames.put(propertyName, name);
}
}
return propertyNames;
}
}

Expand All @@ -1249,7 +1269,9 @@ public static final class ReadResult {
final List<ConfigClass> buildTimeMappings;
final List<ConfigClass> buildTimeRunTimeMappings;
final List<ConfigClass> runTimeMappings;
final Map<Class<?>, ConfigClass> allMappings;
final List<ConfigClass> allMappings;
final Map<Class<?>, ConfigClass> allMappingsByClass;
final Map<PropertyName, String> allMappingsNames;

final Set<String> unknownBuildProperties;
final Set<String> deprecatedRuntimeProperties;
Expand All @@ -1273,7 +1295,9 @@ public ReadResult(final Builder builder) {
this.buildTimeMappings = builder.getBuildTimeMappings();
this.buildTimeRunTimeMappings = builder.getBuildTimeRunTimeMappings();
this.runTimeMappings = builder.getRunTimeMappings();
this.allMappings = mappingsToMap(builder);
this.allMappings = new ArrayList<>(mappingsToMap(builder).values());
this.allMappingsByClass = mappingsToMap(builder);
this.allMappingsNames = ReadOperation.mappingsToNames(allMappings);

this.unknownBuildProperties = builder.getUnknownBuildProperties();
this.deprecatedRuntimeProperties = builder.deprecatedRuntimeProperties;
Expand Down Expand Up @@ -1355,10 +1379,18 @@ public List<ConfigClass> getRunTimeMappings() {
return runTimeMappings;
}

public Map<Class<?>, ConfigClass> getAllMappings() {
public List<ConfigClass> getAllMappings() {
return allMappings;
}

public Map<Class<?>, ConfigClass> getAllMappingsByClass() {
return allMappingsByClass;
}

public Map<PropertyName, String> getAllMappingsNames() {
return allMappingsNames;
}

public Set<String> getUnknownBuildProperties() {
return unknownBuildProperties;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
Expand Down Expand Up @@ -63,6 +64,7 @@
import io.quarkus.runtime.configuration.NameIterator;
import io.quarkus.runtime.configuration.PropertiesUtil;
import io.quarkus.runtime.configuration.QuarkusConfigFactory;
import io.smallrye.config.ConfigMappingInterface;
import io.smallrye.config.ConfigMappings;
import io.smallrye.config.ConfigMappings.ConfigClass;
import io.smallrye.config.Converters;
Expand All @@ -88,9 +90,6 @@ public final class RunTimeConfigurationGenerator {
public static final MethodDescriptor C_READ_CONFIG = MethodDescriptor.ofMethod(CONFIG_CLASS_NAME, "readConfig", void.class);

static final FieldDescriptor C_MAPPED_PROPERTIES = FieldDescriptor.of(CONFIG_CLASS_NAME, "mappedProperties", Set.class);
static final MethodDescriptor C_GENERATE_MAPPED_PROPERTIES = MethodDescriptor.ofMethod(CONFIG_CLASS_NAME,
"generateMappedProperties", Set.class);
static final MethodDescriptor PN_NEW = MethodDescriptor.ofConstructor(PropertyName.class, String.class);
static final FieldDescriptor C_UNKNOWN = FieldDescriptor.of(CONFIG_CLASS_NAME, "unknown", Set.class);
static final FieldDescriptor C_UNKNOWN_RUNTIME = FieldDescriptor.of(CONFIG_CLASS_NAME, "unknownRuntime", Set.class);

Expand Down Expand Up @@ -192,9 +191,13 @@ public final class RunTimeConfigurationGenerator {
static final MethodDescriptor PU_IS_PROPERTY_IN_ROOTS = MethodDescriptor.ofMethod(PropertiesUtil.class, "isPropertyInRoots",
boolean.class, String.class, Set.class);
static final MethodDescriptor HS_NEW = MethodDescriptor.ofConstructor(HashSet.class);
static final MethodDescriptor HS_NEW_SIZED = MethodDescriptor.ofConstructor(HashSet.class, int.class);
static final MethodDescriptor HS_ADD = MethodDescriptor.ofMethod(HashSet.class, "add", boolean.class, Object.class);
static final MethodDescriptor HS_ADD_ALL = MethodDescriptor.ofMethod(HashSet.class, "addAll", boolean.class,
Collection.class);
static final MethodDescriptor HS_CONTAINS = MethodDescriptor.ofMethod(HashSet.class, "contains", boolean.class,
Object.class);
static final MethodDescriptor PN_NEW = MethodDescriptor.ofConstructor(PropertyName.class, String.class);

// todo: more space-efficient sorted map impl
static final MethodDescriptor TM_NEW = MethodDescriptor.ofConstructor(TreeMap.class);
Expand Down Expand Up @@ -262,7 +265,6 @@ public static final class GenerateOperation implements AutoCloseable {
roots = Assert.checkNotNullParam("builder.roots", builder.getBuildTimeReadResult().getAllRoots());
additionalTypes = Assert.checkNotNullParam("additionalTypes", builder.getAdditionalTypes());
cc = ClassCreator.builder().classOutput(classOutput).className(CONFIG_CLASS_NAME).setFinal(true).build();
generateMappedProperties();
generateEmptyParsers();
// not instantiable
try (MethodCreator mc = cc.getMethodCreator(MethodDescriptor.ofConstructor(CONFIG_CLASS_NAME))) {
Expand All @@ -282,14 +284,17 @@ public static final class GenerateOperation implements AutoCloseable {
clinit.setModifiers(Opcodes.ACC_STATIC);

cc.getFieldCreator(C_MAPPED_PROPERTIES).setModifiers(Opcodes.ACC_STATIC);
clinit.writeStaticField(C_MAPPED_PROPERTIES, clinit.invokeStaticMethod(C_GENERATE_MAPPED_PROPERTIES));
clinit.writeStaticField(C_MAPPED_PROPERTIES, clinit.newInstance(HS_NEW_SIZED,
clinit.load((int) ((float) buildTimeConfigResult.getAllMappingsNames().size() / 0.75f + 1.0f))));

cc.getFieldCreator(C_UNKNOWN).setModifiers(Opcodes.ACC_STATIC);
clinit.writeStaticField(C_UNKNOWN, clinit.newInstance(HS_NEW));

cc.getFieldCreator(C_UNKNOWN_RUNTIME).setModifiers(Opcodes.ACC_STATIC);
clinit.writeStaticField(C_UNKNOWN_RUNTIME, clinit.newInstance(HS_NEW));

generateMappedProperties();

clinitNameBuilder = clinit.newInstance(SB_NEW);

// the build time config, which is for user use only (not used by us other than for loading converters)
Expand Down Expand Up @@ -1191,26 +1196,32 @@ private FieldDescriptor getOrCreateConverterInstance(Field field, ConverterType
}

private void generateMappedProperties() {
Set<String> names = new HashSet<>();
for (ConfigClass buildTimeMapping : buildTimeConfigResult.getBuildTimeMappings()) {
names.addAll(ConfigMappings.getProperties(buildTimeMapping).keySet());
}
for (ConfigClass staticConfigMapping : buildTimeConfigResult.getBuildTimeRunTimeMappings()) {
names.addAll(ConfigMappings.getProperties(staticConfigMapping).keySet());
}
for (ConfigClass runtimeConfigMapping : buildTimeConfigResult.getRunTimeMappings()) {
names.addAll(ConfigMappings.getProperties(runtimeConfigMapping).keySet());
MethodDescriptor method = MethodDescriptor.ofMethod(CONFIG_CLASS_NAME, "addMappedProperties", void.class);
MethodCreator mc = cc.getMethodCreator(method);
mc.setModifiers(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC);
for (ConfigClass mapping : buildTimeConfigResult.getAllMappings()) {
mc.invokeStaticMethod(generateMappedProperties(mapping, buildTimeConfigResult.getAllMappingsNames()));
}
Set<PropertyName> propertyNames = PropertiesUtil.toPropertyNames(names);
mc.returnVoid();
mc.close();
clinit.invokeStaticMethod(method);
}

MethodCreator mc = cc.getMethodCreator(C_GENERATE_MAPPED_PROPERTIES);
private MethodDescriptor generateMappedProperties(final ConfigClass mapping,
final Map<PropertyName, String> propertyNames) {
MethodDescriptor method = MethodDescriptor.ofMethod(CONFIG_CLASS_NAME,
"addMappedProperties$" + mapping.getKlass().getName().replace('.', '$'), void.class);
MethodCreator mc = cc.getMethodCreator(method);
mc.setModifiers(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC);
ResultHandle set = mc.newInstance(HS_NEW);
for (PropertyName propertyName : propertyNames) {
mc.invokeVirtualMethod(HS_ADD, set, mc.newInstance(PN_NEW, mc.load(propertyName.getName())));
Map<String, ConfigMappingInterface.Property> properties = ConfigMappings.getProperties(mapping);
ResultHandle set = mc.readStaticField(C_MAPPED_PROPERTIES);
for (String propertyName : properties.keySet()) {
String name = propertyNames.get(new PropertyName(propertyName));
mc.invokeVirtualMethod(HS_ADD, set, mc.newInstance(PN_NEW, mc.load(name)));
}
mc.returnValue(set);
mc.returnVoid();
mc.close();
return method;
}

private void reportUnknown(BytecodeCreator bc, ResultHandle unknownProperty) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package io.quarkus.runtime.configuration;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import io.smallrye.config.PropertyName;

public class PropertiesUtil {
private PropertiesUtil() {
throw new IllegalStateException("Utility class");
Expand Down Expand Up @@ -48,28 +44,4 @@ public static boolean isPropertyInRoot(final String property, final String root)
public static boolean isPropertyQuarkusCompoundName(NameIterator propertyName) {
return propertyName.getName().startsWith("\"quarkus.");
}

public static Set<PropertyName> toPropertyNames(final Set<String> names) {
Map<PropertyName, String> propertyNames = new HashMap<>();
for (String name : names) {
PropertyName propertyName = new PropertyName(name);
if (propertyNames.containsKey(propertyName)) {
String existing = propertyNames.remove(propertyName);
if (existing.length() < name.length()) {
propertyNames.put(new PropertyName(existing), existing);
} else if (existing.length() > name.length()) {
propertyNames.put(propertyName, name);
} else {
if (existing.indexOf('*') <= name.indexOf('*')) {
propertyNames.put(new PropertyName(existing), existing);
} else {
propertyNames.put(propertyName, name);
}
}
} else {
propertyNames.put(propertyName, name);
}
}
return propertyNames.keySet();
}
}
Loading