This is an automated email from the ASF dual-hosted git repository.

heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git

commit 0003ba4b04435ecf5a5a470be5a3b0b95e57d166
Author: Alex Heneveld <[email protected]>
AuthorDate: Fri Jun 23 16:30:21 2023 +0100

    cache service lookup results
    
    saves a not insignificant time because the underlying implementations 
rescan classes;
    we invalidate the cache whenever bundles change or startup completes
---
 .../brooklyn/api/framework/FrameworkLookup.java    | 39 ++++++++++++++++++----
 .../apache/brooklyn/core/mgmt/ha/OsgiManager.java  |  5 +++
 .../core/workflow/steps/CustomWorkflowStep.java    |  1 +
 .../util/core/task/BasicExecutionManager.java      |  8 +++--
 .../brooklyn/launcher/osgi/OsgiLauncherImpl.java   |  3 ++
 5 files changed, 47 insertions(+), 9 deletions(-)

diff --git 
a/api/src/main/java/org/apache/brooklyn/api/framework/FrameworkLookup.java 
b/api/src/main/java/org/apache/brooklyn/api/framework/FrameworkLookup.java
index 079117a4a1..829bfc8fc0 100644
--- a/api/src/main/java/org/apache/brooklyn/api/framework/FrameworkLookup.java
+++ b/api/src/main/java/org/apache/brooklyn/api/framework/FrameworkLookup.java
@@ -18,16 +18,14 @@
  */
 package org.apache.brooklyn.api.framework;
 
+import com.google.common.collect.Maps;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.osgi.OsgiUtil;
 import org.osgi.framework.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.ServiceLoader;
+import java.util.*;
 
 /**
  * A utility to fetch an instance of a class from either OSGI if available, or 
by a Service Loader otherwise.
@@ -42,11 +40,28 @@ import java.util.ServiceLoader;
  * which this code does not do.  Therefore this class is not suitable for use 
in a situation where client code needs
  * to take account of services coming and going, and explicitly avoid using 
the service when its reference count has
  * gone to zero.
+ *
+ * This is achieved by clients looking up services as they need,
+ * and maintaining a cache here.
+ *
+ * The cache is explicitly invalidated when bundles are installed and when 
brooklyn finishes loading.
  */
 public class FrameworkLookup {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(FrameworkLookup.class);
 
+    private static boolean cachingEnabled = false;
+    public static void setCachingEnabled(boolean cachingEnabled) {
+        FrameworkLookup.cachingEnabled = cachingEnabled;
+    }
+
+    public static void invalidateCaches() {
+        cacheOfSingleInstancesWithNoLoader.clear();
+    }
+
+    static Map<Class,Maybe> cacheOfSingleInstancesWithNoLoader = 
Maps.newConcurrentMap();
+    static Map<Class,Iterable> cacheOfAllInstancesWithNoLoader = 
Maps.newConcurrentMap();
+
     /**
      * Find an instance of the given class in the framework.
      * This first performs an OSGI lookup if the OSGI framework is available. 
If it is not then it falls back to
@@ -72,13 +87,18 @@ public class FrameworkLookup {
      * @return  A maybe of the instance found in the framework.
      */
     public static <T> Maybe<T> lookup (Class<T> clazz, ClassLoader loader) {
-
         Maybe<T> result;
+        if (loader==null) {
+            result = cacheOfSingleInstancesWithNoLoader.get(clazz);
+            if (result!=null) return result;
+        }
+
         if (OsgiUtil.isBrooklynInsideFramework()) {
             result = lookupInOsgi(clazz);
         } else {
             result = lookupViaServiceLoader(clazz, loader);
         }
+        cacheOfSingleInstancesWithNoLoader.put(clazz, result);
 
         return result;
     }
@@ -108,13 +128,20 @@ public class FrameworkLookup {
      * @return  An iterable over the instances found in the framework.
      */
     public static <T> Iterable<T> lookupAll(Class<T> clazz, ClassLoader 
loader) {
-
         Iterable<T> result;
+
+        if (loader==null) {
+            result = cacheOfAllInstancesWithNoLoader.get(clazz);
+            if (result!=null) return result;
+        }
+
         if (OsgiUtil.isBrooklynInsideFramework()) {
             result = lookupAllInOsgi(clazz);
         } else {
             result = lookupAllViaServiceLoader(clazz, loader);
         }
+        cacheOfAllInstancesWithNoLoader.put(clazz, result);
+
         return result;
     }
 
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java 
b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
index 7482dd88a3..32588c6ee7 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
@@ -37,6 +37,7 @@ import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Supplier;
 import javax.annotation.Nullable;
 import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
+import org.apache.brooklyn.api.framework.FrameworkLookup;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
@@ -155,6 +156,7 @@ public class OsgiManager {
             if (Strings.isNonBlank(result.getMetadata().getUrl())) {
                 managedBundlesUidByUrl.put(result.getMetadata().getUrl(), 
result.getMetadata().getId());
             }
+            FrameworkLookup.invalidateCaches();
         }
 
         private File fileFor(ManagedBundle managedBundle) {
@@ -178,6 +180,7 @@ public class OsgiManager {
             
managedBundlesRecord.managedBundlesUidByUrl.remove(bundleMetadata.getUrl());
             removeInstalledWrapperBundle(bundleMetadata);
             fileFor(bundleMetadata).delete();
+            FrameworkLookup.invalidateCaches();
             return true;
         }
 
@@ -202,6 +205,7 @@ public class OsgiManager {
             }
 
             ManagedBundle mbBak = 
managedBundlesByUid.put(result.getMetadata().getId(), result.getMetadata());
+            FrameworkLookup.invalidateCaches();
 
             return Pair.of(fBak, mbBak);
         }
@@ -221,6 +225,7 @@ public class OsgiManager {
             fBak.renameTo(fCached);
 
             managedBundlesByUid.put(result.getMetadata().getId(), mbBak);
+            FrameworkLookup.invalidateCaches();
 
             return fCached;
         }
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/CustomWorkflowStep.java
 
b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/CustomWorkflowStep.java
index 0fdd8ab981..d1925d2327 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/CustomWorkflowStep.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/CustomWorkflowStep.java
@@ -132,6 +132,7 @@ public class CustomWorkflowStep extends 
WorkflowStepDefinition implements Workfl
         retention = (String) input.remove("retention");
     }
 
+    /** disabled or count, hashes, etc; see {@link WorkflowRetentionParser} or 
documentation for full info */
     protected String retention;
 
     /** What to run this set of steps against, either an entity to run in that 
context, 'children' or 'members' to run over those, a range eg 1..10,  or a 
list (often in a variable) to run over elements of the list */
diff --git 
a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
 
b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
index e2cde9a050..97e63bedce 100644
--- 
a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
+++ 
b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
@@ -1128,6 +1128,7 @@ public class BasicExecutionManager implements 
ExecutionManager {
     private static class TaskLookup implements Supplier<Task<?>> {
         // this class is not meant to be serialized, but if it is, make sure 
exec mgr doesn't sneak in
         transient BasicExecutionManager mgr;
+        transient Task<?> cachedResult;
 
         String id;
         String displayName;
@@ -1144,9 +1145,10 @@ public class BasicExecutionManager implements 
ExecutionManager {
         @Override
         public Task<?> get() {
             if (mgr == null) return gone();
-            Task<?> result = mgr.getTask(id);
-            if (result != null) return result;
-            return gone();
+
+            cachedResult = mgr.getTask(id);
+            if (cachedResult==null) cachedResult = gone();
+            return cachedResult;
         }
 
         private <T> Task<T> gone() {
diff --git 
a/karaf/init/src/main/java/org/apache/brooklyn/launcher/osgi/OsgiLauncherImpl.java
 
b/karaf/init/src/main/java/org/apache/brooklyn/launcher/osgi/OsgiLauncherImpl.java
index 64edcfa702..76bc0d21af 100644
--- 
a/karaf/init/src/main/java/org/apache/brooklyn/launcher/osgi/OsgiLauncherImpl.java
+++ 
b/karaf/init/src/main/java/org/apache/brooklyn/launcher/osgi/OsgiLauncherImpl.java
@@ -21,6 +21,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.framework.FrameworkLookup;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.core.BrooklynVersionService;
@@ -305,6 +307,7 @@ public class OsgiLauncherImpl extends 
BasicLauncher<OsgiLauncherImpl> implements
             
((ManagementContextInternal)getManagementContext()).getBrooklynProperties().put(OsgiManager.OSGI_STARTUP_COMPLETE,
 true);
             startupTimer.stop();
             LOG.info("Brooklyn initialization (part two) complete after {}", 
startupTimer.toString());
+            FrameworkLookup.invalidateCaches();
         }
     }
 

Reply via email to