From c28403cb2652fa2f79384292d1e864f5154fc859 Mon Sep 17 00:00:00 2001
From: worku005 <dirk-jan.vanworkum@wur.nl>
Date: Mon, 2 Dec 2024 13:30:32 +0100
Subject: [PATCH] introducing small class to handle stderr for mcl to fix
 hanging issue

---
 .../construction/grouping/Grouping.java       | 33 ++++++------
 .../java/nl/wur/bif/pantools/utils/Utils.java | 51 +++++++++++++++----
 2 files changed, 57 insertions(+), 27 deletions(-)

diff --git a/src/main/java/nl/wur/bif/pantools/construction/grouping/Grouping.java b/src/main/java/nl/wur/bif/pantools/construction/grouping/Grouping.java
index 28c709209..fc338b509 100644
--- a/src/main/java/nl/wur/bif/pantools/construction/grouping/Grouping.java
+++ b/src/main/java/nl/wur/bif/pantools/construction/grouping/Grouping.java
@@ -717,8 +717,7 @@ public class Grouping {
          * @param pangenome_path The path to the current graph database
          */
         void break_component(LinkedList<Node> component, String pangenome_path) throws InterruptedException {
-            int group_size, wating_time, time;
-            double infl;
+            int group_size;
             LinkedList<Node> homology_group, singletons_group = new LinkedList();
             String graph_path, clusters_path, line, command;
             BufferedReader clusters_file;
@@ -726,25 +725,23 @@ public class Grouping {
             group_size = component.size();
             graph_path = pangenome_path + "/" + component.getFirst().getId() + ".graph";
             clusters_path = pangenome_path + "/" + component.getFirst().getId() + ".clusters";
-        // Prepare the input file for MCL
+
+            // Prepare the input file for MCL
             write_similaity_matrix(component, graph_path);
-        //  Estimate the run-time of MCL
-            time = wating_time = 1 + (int) Math.round(group_size / 100000000.0 * group_size);
-            for( infl = MCL_INFLATION; infl < 30; infl += 0.5) {
-                command = "mcl " + graph_path + " --abc -I " + infl + " -o " + clusters_path + " -overlap keep";
-                //Pantools.logger.info(command);
-                if(executeCommand_for(command, wating_time))
-                    break;
-                if((tmp_file = new File(clusters_path)).exists())
-                    tmp_file.delete();
-                wating_time += time;
-            }
-            if (infl >= 30) {
+
+            // Run MCL
+            command = "mcl " + graph_path + " --abc -I " + MCL_INFLATION + " -o " + clusters_path + " -overlap keep -V all";
+            Pantools.logger.debug(command);
+            if (!executeCommand_for(command, 5)) {
                 Pantools.logger.info("Failed to split group ID = {}", component.getFirst().getId());
                 homology_groups_list.put(component);
+                if ((tmp_file = new File(clusters_path)).exists()) {
+                    tmp_file.delete();
+                }
             } else {
+                // Read the output of MCL and create homology groups
                 try (Transaction tx = GRAPH_DB.beginTx()) {
-                    try{
+                    try {
                         clusters_file = new BufferedReader(new FileReader(clusters_path));
                         final List<Set<Long>> cluster = new ArrayList<>();
                         // For each line of the MCL output
@@ -772,7 +769,7 @@ public class Grouping {
                         clusters_file.close();
                         new File(clusters_path).delete();
                         new File(graph_path).delete();
-                    }catch (IOException ex) {
+                    } catch (IOException ex) {
                         Pantools.logger.info(ex.getMessage());
                     }
                     tx.success();
@@ -2994,4 +2991,4 @@ public class Grouping {
             tx.success();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/nl/wur/bif/pantools/utils/Utils.java b/src/main/java/nl/wur/bif/pantools/utils/Utils.java
index 084d7e770..0af62a900 100644
--- a/src/main/java/nl/wur/bif/pantools/utils/Utils.java
+++ b/src/main/java/nl/wur/bif/pantools/utils/Utils.java
@@ -571,19 +571,52 @@ public final class Utils {
      * Executes a shell command in a limited number of seconds.
      *
      * @param command The command
-     * @param seconds The number of seconds
+     * @param timeout The number of seconds before the command is killed
      * @return The output of the bash command
      */
-    public static boolean executeCommand_for(String command, int seconds) {
-        Process p;
-        boolean success = false;
+    public static boolean executeCommand_for(String command, int timeout) {
+        Process process = null;
         try {
-            p = Runtime.getRuntime().exec(command);
-            success = p.waitFor(seconds, TimeUnit.SECONDS);
-        } catch (Exception e) {
-            e.printStackTrace();
+            process = Runtime.getRuntime().exec(command);
+            StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream()); //to make sure the process does not hang
+            StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream()); //to make sure the process does not hang
+
+            outputGobbler.start();
+            errorGobbler.start();
+
+            boolean finished = process.waitFor(timeout, TimeUnit.SECONDS);
+            outputGobbler.join();
+            errorGobbler.join();
+
+            return finished && process.exitValue() == 0;
+        } catch (IOException | InterruptedException e) {
+            Pantools.logger.error("Error executing command: {}", command, e);
+            return false;
+        } finally {
+            if (process != null) {
+                process.destroy();
+            }
+        }
+    }
+
+    private static class StreamGobbler extends Thread {
+        private final InputStream inputStream;
+
+        public StreamGobbler(InputStream inputStream) {
+            this.inputStream = inputStream;
+        }
+
+        @Override
+        public void run() {
+            try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    Pantools.logger.trace("{}", line);
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
         }
-        return success;
     }
 
     /**
-- 
GitLab