This is an automated email from the ASF dual-hosted git repository. vitalii pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/drill.git
commit 9dec5144f669b1fb97208a0b9c848af14b7cbccf Author: Igor Guzenko <ihor.huzenko....@gmail.com> AuthorDate: Wed Dec 19 13:45:02 2018 +0200 DRILL-6912: NPE when other drillbit is already running closes #1577 --- .../org/apache/drill/exec/server/Drillbit.java | 9 ++++- .../apache/drill/test/TestGracefulShutdown.java | 43 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/Drillbit.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/Drillbit.java index 4c595a2..8d41397 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/Drillbit.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/Drillbit.java @@ -98,7 +98,7 @@ public class Drillbit implements AutoCloseable { private DrillbitStateManager stateManager; private boolean quiescentMode; private boolean forcefulShutdown = false; - GracefulShutdownThread gracefulShutdownThread; + private GracefulShutdownThread gracefulShutdownThread; private boolean interruptPollShutdown = true; public void setQuiescentMode(boolean quiescentMode) { @@ -196,6 +196,7 @@ public class Drillbit implements AutoCloseable { public void run() throws Exception { final Stopwatch w = Stopwatch.createStarted(); logger.debug("Startup begun."); + gracefulShutdownThread = new GracefulShutdownThread(this, new StackTrace()); coord.start(10000); stateManager.setState(DrillbitState.ONLINE); storeProvider.start(); @@ -222,7 +223,6 @@ public class Drillbit implements AutoCloseable { drillbitContext.startRM(); Runtime.getRuntime().addShutdownHook(new ShutdownThread(this, new StackTrace())); - gracefulShutdownThread = new GracefulShutdownThread(this, new StackTrace()); gracefulShutdownThread.start(); logger.info("Startup completed ({} ms).", w.elapsed(TimeUnit.MILLISECONDS)); } @@ -470,6 +470,11 @@ public class Drillbit implements AutoCloseable { return manager.getContext(); } + @VisibleForTesting + public GracefulShutdownThread getGracefulShutdownThread() { + return gracefulShutdownThread; + } + public static void main(final String[] cli) throws DrillbitStartupException { final StartupOptions options = StartupOptions.parse(cli); start(options); diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/TestGracefulShutdown.java b/exec/java-exec/src/test/java/org/apache/drill/test/TestGracefulShutdown.java index 9e3721c..9d649ba 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/test/TestGracefulShutdown.java +++ b/exec/java-exec/src/test/java/org/apache/drill/test/TestGracefulShutdown.java @@ -17,9 +17,11 @@ */ package org.apache.drill.test; import org.apache.drill.categories.SlowTest; +import org.apache.drill.common.exceptions.UserException; import org.apache.drill.exec.ExecConstants; import org.apache.drill.exec.proto.CoordinationProtos.DrillbitEndpoint; import org.apache.drill.exec.server.Drillbit; +import org.apache.hadoop.net.ServerSocketUtil; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Rule; @@ -36,6 +38,9 @@ import java.net.URL; import java.nio.file.Path; import java.util.Collection; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; @Category({SlowTest.class}) @@ -174,6 +179,44 @@ public class TestGracefulShutdown extends BaseTestQuery { } } + @Test // DRILL-6912 + public void gracefulShutdownThreadShouldBeInitializedBeforeClosingDrillbit() throws Exception { + Drillbit drillbit = null; + Drillbit drillbitWithSamePort = null; + + int userPort = ServerSocketUtil.getPort(31170, 300); + int bitPort = ServerSocketUtil.getPort(31180, 300); + ClusterFixtureBuilder fixtureBuilder = ClusterFixture.bareBuilder(dirTestWatcher).withLocalZk() + .configProperty(ExecConstants.INITIAL_USER_PORT, userPort) + .configProperty(ExecConstants.INITIAL_BIT_PORT, bitPort); + try (ClusterFixture clusterFixture = fixtureBuilder.build()) { + drillbit = clusterFixture.drillbit(); + + // creating another drillbit instance using same config + drillbitWithSamePort = new Drillbit(clusterFixture.config(), fixtureBuilder.configBuilder().getDefinitions(), + clusterFixture.serviceSet()); + + try { + drillbitWithSamePort.run(); + fail("drillbitWithSamePort.run() should throw UserException"); + } catch (UserException e) { + // it's expected that second drillbit can't be started because port is busy + assertThat(e.getMessage(), containsString("RESOURCE ERROR: Drillbit could not bind to port")); + } + } finally { + // preconditions + assertNotNull(drillbit); + assertNotNull(drillbitWithSamePort); + assertNotNull("gracefulShutdownThread should be initialized, otherwise NPE will be thrown from close()", + drillbit.getGracefulShutdownThread()); + // main test case + assertNotNull("gracefulShutdownThread should be initialized, otherwise NPE will be thrown from close()", + drillbitWithSamePort.getGracefulShutdownThread()); + drillbit.close(); + drillbitWithSamePort.close(); + } + } + private static boolean waitAndAssertDrillbitCount(ClusterFixture cluster, int zkRefresh) throws InterruptedException { while (true) {