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


The following commit(s) were added to refs/heads/master by this push:
     new da1653b  try to clean osgi so launcher build doesn't break FS limits
da1653b is described below

commit da1653b660334660dbf1334a179d92f0d7da65d7
Author: Alex Heneveld <[email protected]>
AuthorDate: Sat Aug 7 03:33:43 2021 +0100

    try to clean osgi so launcher build doesn't break FS limits
    
    OSGi cycles leak a few hundred open files; can't solve it, though code in 
here tries to;
    
    ultimately just enable osgi reuse for the test...
---
 .../apache/brooklyn/core/mgmt/ha/OsgiManager.java  | 41 +++++++++++++++++
 .../BrooklynLauncherUpgradeCatalogOsgiTest.java    |  6 +--
 .../java/org/apache/brooklyn/util/guava/Maybe.java | 53 ++++++++++++++++++++++
 3 files changed, 97 insertions(+), 3 deletions(-)

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 85418e9..835ae44 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
@@ -29,6 +29,9 @@ import java.io.*;
 import java.net.URL;
 import java.util.*;
 import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Supplier;
@@ -59,6 +62,7 @@ import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.exceptions.ReferenceWithError;
 import org.apache.brooklyn.util.exceptions.UserFacingException;
 import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.javalang.Reflections;
 import org.apache.brooklyn.util.os.Os;
 import org.apache.brooklyn.util.os.Os.DeletionResult;
 import org.apache.brooklyn.util.osgi.VersionedName;
@@ -70,6 +74,7 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
 import org.osgi.framework.launch.Framework;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -296,7 +301,43 @@ public class OsgiManager {
         }
         
         if (!reuseFramework || !REUSED_FRAMEWORKS_ARE_KEPT_RUNNING) {
+            try {
+                for (Bundle b: framework.getBundleContext().getBundles()) {
+                    if ((bundlesAtStartup==null || 
!bundlesAtStartup.contains(b)) && (b!=framework)) {
+                        try {
+                            log.info("Uninstalling "+b+" from OSGi container");
+                            b.uninstall();
+                        } catch (Exception e) {
+                            Exceptions.propagateIfFatal(e);
+                            log.warn("Unable to uninstall "+b+": "+e, e);
+                        }
+                    }
+                }
+
+                framework.stop();
+                final FrameworkEvent fe = 
framework.waitForStop(Duration.seconds(30).toMilliseconds());
+                log.debug("Stopped OSGi framework: "+fe);
+            } catch (Exception e) {
+                throw Exceptions.propagate(e);
+            }
             Osgis.ungetFramework(framework);
+
+            // aggressively clean up, as Felix leaks threadpools and other 
objects;
+            // but even with this _something_ is clogging up the app 
classloader
+            // which is causing file handles to leak badly;
+
+            Reflections.getFieldValueMaybe(framework, "m_resolver")
+                .mapMaybe(resolver -> Reflections.getFieldValueMaybe(resolver, 
"m_executor"))
+                .transformNow(ex -> {
+                    if (ex instanceof ExecutorService) {
+                        return ((ExecutorService) ex).shutdownNow();
+                    }
+                    return null;
+                });
+
+            System.gc(); System.gc();
+            System.runFinalization(); System.runFinalization();
+            System.gc(); System.gc();
         }
         
         if (reuseFramework) {
diff --git 
a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java
 
b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java
index c7cc83d..a3f4c32 100644
--- 
a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java
+++ 
b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java
@@ -61,7 +61,7 @@ public class BrooklynLauncherUpgradeCatalogOsgiTest extends 
AbstractBrooklynLaun
     
     @Override
     protected boolean reuseOsgi() {
-        return false;
+        return true;
     }
 
     private BrooklynLauncher newLauncherForTests(String catalogInitial) {
@@ -216,7 +216,7 @@ public class BrooklynLauncherUpgradeCatalogOsgiTest extends 
AbstractBrooklynLaun
     public void testForciblyRemovedBundleNotAdded() throws Exception {
         runForciblyRemovedBundleNotAdded(true);
     }
-    
+
     @Test
     public void testForciblyRemovedBundleNotAddedWithNoUpgradeTarget() throws 
Exception {
         runForciblyRemovedBundleNotAdded(false);
@@ -295,7 +295,7 @@ public class BrooklynLauncherUpgradeCatalogOsgiTest extends 
AbstractBrooklynLaun
 
         launcher.terminate();
     }
-    
+
     @Test
     public void testForciblyRemovedBundleNotAddedWhenReferencedByName() throws 
Exception {
         VersionedName one_1_0_0 = VersionedName.fromString("one:1.0.0");
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java 
b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
index e319503..5649f88 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
@@ -403,6 +403,10 @@ public abstract class Maybe<T> implements Serializable, 
Supplier<T> {
         return new MaybeTransforming(this, f);
     }
 
+    public <V> Maybe<V> mapMaybe(final Function<? super T, Maybe<V>> f) {
+        return new MaybeTransformingMaybe(this, f);
+    }
+
     private <V> Maybe<V> mapKeptForDeserializingOld(final Function<? super T, 
V> f) {
         if (isPresent()) return new AbstractPresent<V>() {
             private static final long serialVersionUID = 325089324325L;
@@ -440,6 +444,55 @@ public abstract class Maybe<T> implements Serializable, 
Supplier<T> {
         }
     }
 
+    public static class MaybeTransformingMaybe<T,V> extends Maybe<V> {
+        private static final long serialVersionUID = 325089324325L;
+        private final Maybe<T> input;
+        private final Function<? super T, Maybe<V>> f;
+        private boolean gotten = false;
+        private Maybe<V> gottenObject;
+
+        public MaybeTransformingMaybe(Maybe<T> input, Function<? super 
T,Maybe<V>> f) {
+            this.input = input;
+            this.f = f;
+        }
+
+        @Override
+        public boolean isPresent() {
+            if (!input.isPresent()) return false;
+            evaluate();
+            return gottenObject.isPresent();
+        }
+
+        public void evaluate() {
+            if (!gotten) {
+                synchronized (this) {
+                    if (!gotten) {
+                        gotten = true;
+                        if (!input.isPresent()) {
+                            gottenObject = Maybe.castAbsent(input);
+                            return;
+                        }
+                        gottenObject = f.apply(input.get());
+                        if (gottenObject==null) {
+                            gottenObject = Maybe.absent("transformation 
yielded null rather than a maybe");
+                        }
+                    }
+                }
+            }
+        }
+
+        @Override
+        public V get() {
+            evaluate();
+            return gottenObject.get();
+        }
+
+        @Override
+        public boolean isNull() {
+            return isPresent() ? get()==null : input.isNull();
+        }
+    }
+
     /** applies a function immediately if a value is present and returns the 
transformed object,
      * or returns the original absence */
     public <V> Maybe<V> transformNow(final Function<? super T, V> f) {

Reply via email to