You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bookkeeper.apache.org by iv...@apache.org on 2018/02/19 20:18:31 UTC

[bookkeeper] branch master updated: Cleanup threads from old clients in BC tests

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

ivank pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git


The following commit(s) were added to refs/heads/master by this push:
     new d4277c0  Cleanup threads from old clients in BC tests
d4277c0 is described below

commit d4277c06f62f680dba9383e68c0699c343e4e5ca
Author: Ivan Kelly <iv...@apache.org>
AuthorDate: Mon Feb 19 21:18:25 2018 +0100

    Cleanup threads from old clients in BC tests
    
    Some old clients don't clean up their threads correctly. This patch
    introduces a thread reaper, which will check if a test has left any
    threads running, and try to clean them up if they have.
    
    Author: Ivan Kelly <iv...@apache.org>
    
    Reviewers: Sijie Guo <si...@apache.org>
    
    This closes #1177 from ivankelly/thread-reaper
---
 .../backwardcompat/TestCompatOldClients.groovy     | 13 +++--
 .../org/apache/bookkeeper/tests/ThreadReaper.java  | 66 ++++++++++++++++++++++
 2 files changed, 75 insertions(+), 4 deletions(-)

diff --git a/tests/backward-compat/current-server-old-clients/src/test/groovy/org/apache/bookkeeper/tests/backwardcompat/TestCompatOldClients.groovy b/tests/backward-compat/current-server-old-clients/src/test/groovy/org/apache/bookkeeper/tests/backwardcompat/TestCompatOldClients.groovy
index 9c237cc..a527567 100644
--- a/tests/backward-compat/current-server-old-clients/src/test/groovy/org/apache/bookkeeper/tests/backwardcompat/TestCompatOldClients.groovy
+++ b/tests/backward-compat/current-server-old-clients/src/test/groovy/org/apache/bookkeeper/tests/backwardcompat/TestCompatOldClients.groovy
@@ -21,6 +21,7 @@ import com.github.dockerjava.api.DockerClient
 
 import org.apache.bookkeeper.tests.BookKeeperClusterUtils
 import org.apache.bookkeeper.tests.MavenClassLoader
+import org.apache.bookkeeper.tests.ThreadReaper
 
 import org.jboss.arquillian.junit.Arquillian
 import org.jboss.arquillian.test.api.ArquillianResource
@@ -110,14 +111,16 @@ class TestCompatOldClients {
     @Test
     public void testNewClientFencesOldClient() throws Exception {
         oldClientVersions.each{
-            testFencingOldClient(it, currentVersion)
+            def version = it
+            ThreadReaper.runWithReaper({ testFencingOldClient(version, currentVersion) })
         }
     }
 
     @Test
     public void testOldClientFencesOldClient() throws Exception {
         oldClientVersions.each{
-            testFencingOldClient(it, it)
+            def version = it
+            ThreadReaper.runWithReaper({ testFencingOldClient(version, version) })
         }
     }
 
@@ -161,14 +164,16 @@ class TestCompatOldClients {
     @Test
     public void testOldClientReadsNewClient() throws Exception {
         oldClientVersions.each{
-            testReads(currentVersion, it)
+            def version = it
+            ThreadReaper.runWithReaper({ testReads(currentVersion, version) })
         }
     }
 
     @Test
     public void testNewClientReadsNewClient() throws Exception {
         oldClientVersions.each{
-            testReads(it, currentVersion)
+            def version = it
+            ThreadReaper.runWithReaper({ testReads(version, currentVersion) })
         }
     }
 }
diff --git a/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/ThreadReaper.java b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/ThreadReaper.java
new file mode 100644
index 0000000..abccbd9
--- /dev/null
+++ b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/ThreadReaper.java
@@ -0,0 +1,66 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.bookkeeper.tests;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ThreadReaper {
+    private static final Logger LOG = LoggerFactory.getLogger(ThreadReaper.class);
+    private static AtomicInteger groupId = new AtomicInteger(0);
+
+    public static <T> T runWithReaper(Callable<T> callable) throws Exception {
+        ThreadGroup tg = new ThreadGroup("reaper-group-" + groupId.incrementAndGet());
+        CompletableFuture<T> promise = new CompletableFuture<>();
+        Thread t = new Thread(tg, () -> {
+                try {
+                    promise.complete(callable.call());
+                } catch (Throwable ex) {
+                    promise.completeExceptionally(ex);
+                }
+        }, "reapable-thread");
+        t.start();
+        T ret = promise.get();
+
+        int i = 30; // try to clean up for 3 seconds
+        while (tg.activeCount() > 0 && i > 0) {
+            tg.interrupt();
+            Thread.sleep(100);
+            LOG.info("{} threads still alive", tg.activeCount());
+            i--;
+        }
+        if (tg.activeCount() == 0) {
+            LOG.info("All threads in reaper group dead");
+        } else {
+            Thread[] threads = new Thread[tg.activeCount()];
+            int found = tg.enumerate(threads);
+            LOG.info("Leaked {} threads", found);
+            for (int j = 0; j < found; j++) {
+                LOG.info("Leaked thread {}", threads[j]);
+            }
+        }
+        return ret;
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
ivank@apache.org.