From f9a76860bba36d0cf6555b496358d41554f81a44 Mon Sep 17 00:00:00 2001 From: Mattie Fu Date: Mon, 9 Mar 2026 10:20:21 -0400 Subject: [PATCH 1/2] fix: Fix race in emulator controller --- .../emulator/core/EmulatorController.java | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/google-cloud-bigtable-emulator-core/src/main/java/com/google/cloud/bigtable/emulator/core/EmulatorController.java b/google-cloud-bigtable-emulator-core/src/main/java/com/google/cloud/bigtable/emulator/core/EmulatorController.java index d39c263faf..8fc9be1b1e 100644 --- a/google-cloud-bigtable-emulator-core/src/main/java/com/google/cloud/bigtable/emulator/core/EmulatorController.java +++ b/google-cloud-bigtable-emulator-core/src/main/java/com/google/cloud/bigtable/emulator/core/EmulatorController.java @@ -44,9 +44,12 @@ public class EmulatorController { private final Path executable; private Process process; + private Thread stdoutThread; + private Thread stderrThread; private boolean isStopped = true; private Thread shutdownHook; + private int port; public static EmulatorController createFromPath(Path path) { @@ -127,8 +130,8 @@ public synchronized void start(int port) throw e; } } - pipeStreamToLog(process.getInputStream(), Level.INFO); - pipeStreamToLog(process.getErrorStream(), Level.WARNING); + Thread stdoutThread = pipeStreamToLog(process.getInputStream(), Level.INFO); + Thread stderrThread = pipeStreamToLog(process.getErrorStream(), Level.WARNING); isStopped = false; shutdownHook = @@ -164,6 +167,23 @@ public synchronized void stop() { } finally { isStopped = true; process.destroy(); + + try { + process.waitFor(); + if (stdoutThread != null) { + stdoutThread.join(); + } + if (stderrThread != null) { + stderrThread.join(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.log(Level.WARNING, "Interrupted while waiting for emulator to stop", e); + } finally { + stdoutThread = null; + stderrThread = null; + process = null; + } } } @@ -239,7 +259,7 @@ private static void waitForPort(int port) throws InterruptedException, TimeoutEx } /** Creates a thread that will pipe an {@link InputStream} to this class' Logger. */ - private static void pipeStreamToLog(final InputStream stream, final Level level) { + private static Thread pipeStreamToLog(final InputStream stream, final Level level) { final BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); Thread thread = @@ -258,6 +278,7 @@ private static void pipeStreamToLog(final InputStream stream, final Level level) }); thread.setDaemon(true); thread.start(); + return thread; } // } From b2aa81b3dee1353eb5c0ec9828378cd0657e4c22 Mon Sep 17 00:00:00 2001 From: Mattie Fu Date: Mon, 9 Mar 2026 10:44:50 -0400 Subject: [PATCH 2/2] format --- .../google/cloud/bigtable/emulator/core/EmulatorController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/google-cloud-bigtable-emulator-core/src/main/java/com/google/cloud/bigtable/emulator/core/EmulatorController.java b/google-cloud-bigtable-emulator-core/src/main/java/com/google/cloud/bigtable/emulator/core/EmulatorController.java index 8fc9be1b1e..960581483b 100644 --- a/google-cloud-bigtable-emulator-core/src/main/java/com/google/cloud/bigtable/emulator/core/EmulatorController.java +++ b/google-cloud-bigtable-emulator-core/src/main/java/com/google/cloud/bigtable/emulator/core/EmulatorController.java @@ -49,7 +49,6 @@ public class EmulatorController { private boolean isStopped = true; private Thread shutdownHook; - private int port; public static EmulatorController createFromPath(Path path) {