From a1ff159d77ceffd5ec9d3c7cf95b652ce7eaf174 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Tue, 21 Sep 2021 13:36:00 +1000 Subject: [PATCH] ArC build time perf improvement This removes the need to iterate over all beans when performing resolution. For a project with 2k injection points this saves close to 0.5s on my desktop. --- .../quarkus/arc/processor/BeanDeployment.java | 27 +++++++++++++++++++ .../arc/processor/BeanResolverImpl.java | 12 +++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java index 0a814bda4d4862..86caf3c7b78e7c 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java @@ -68,6 +68,7 @@ public class BeanDeployment { private final Map stereotypes; private final List beans; + private volatile Map> beansByType = null; private final List interceptors; private final List decorators; @@ -231,6 +232,7 @@ BeanRegistrar.RegistrationContext registerBeans(List beanRegistra List injectionPoints = new ArrayList<>(); this.beans.addAll(findBeans(initBeanDefiningAnnotations(beanDefiningAnnotations, stereotypes.keySet()), observers, injectionPoints, jtaCapabilities)); + beansByType = null; // Note that we need to use view of the collections to reflect further additions, e.g. synthetic beans and observers buildContextPut(Key.BEANS.asString(), Collections.unmodifiableList(beans)); buildContextPut(Key.OBSERVERS.asString(), Collections.unmodifiableList(observers)); @@ -375,6 +377,7 @@ private Set removeUnusedBeans(Set declaresObserver, List
 removableInjectionPoints = removableBeans.stream()
                     .flatMap(d -> d.getAllInjectionPoints().stream()).collect(Collectors.toList());
@@ -407,6 +410,29 @@ public Collection getBeans() {
         return Collections.unmodifiableList(beans);
     }
 
+    public Collection getBeansByType(Type type) {
+        Map> byType = beansByType;
+        if (byType == null) {
+            synchronized (this) {
+                byType = beansByType;
+                if (byType == null) {
+                    byType = new HashMap<>();
+                    for (var i : beans) {
+                        for (var t : i.types) {
+                            byType.computeIfAbsent(t, (s) -> new ArrayList<>()).add(i);
+                        }
+                    }
+                    this.beansByType = byType;
+                }
+            }
+        }
+        var ret = byType.get(type);
+        if (ret == null) {
+            return Collections.emptyList();
+        }
+        return Collections.unmodifiableList(ret);
+    }
+
     public Collection getRemovedBeans() {
         return Collections.unmodifiableSet(removedBeans);
     }
@@ -1126,6 +1152,7 @@ private void addSyntheticBean(BeanInfo bean) {
             }
         }
         beans.add(bean);
+        beansByType = null;
     }
 
     private void addSyntheticObserver(ObserverConfigurator configurator) {
diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanResolverImpl.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanResolverImpl.java
index a085f58197861a..32297915115373 100644
--- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanResolverImpl.java
+++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanResolverImpl.java
@@ -9,6 +9,7 @@
 
 import io.quarkus.arc.processor.InjectionPointInfo.TypeAndQualifiers;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -81,7 +82,11 @@ List resolve(TypeAndQualifiers typeAndQualifiers) {
 
     private List findMatching(TypeAndQualifiers typeAndQualifiers) {
         List resolved = new ArrayList<>();
-        for (BeanInfo b : beanDeployment.getBeans()) {
+        //optimisation for the simple class case
+        Collection potentialBeans = typeAndQualifiers.type.kind() == CLASS
+                ? beanDeployment.getBeansByType(typeAndQualifiers.type)
+                : beanDeployment.getBeans();
+        for (BeanInfo b : potentialBeans) {
             if (Beans.matches(b, typeAndQualifiers)) {
                 resolved.add(b);
             }
@@ -91,7 +96,10 @@ private List findMatching(TypeAndQualifiers typeAndQualifiers) {
 
     List findTypeMatching(Type type) {
         List resolved = new ArrayList<>();
-        for (BeanInfo b : beanDeployment.getBeans()) {
+        //optimisation for the simple class case
+        Collection potentialBeans = type.kind() == CLASS ? beanDeployment.getBeansByType(type)
+                : beanDeployment.getBeans();
+        for (BeanInfo b : potentialBeans) {
             if (Beans.matchesType(b, type)) {
                 resolved.add(b);
             }