You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by mb...@apache.org on 2016/09/28 20:43:50 UTC

asterixdb git commit: Audit work queue blocks/waits, AbstractWork Not Runnable

Repository: asterixdb
Updated Branches:
  refs/heads/master 6277d155a -> 3b5c3c621


Audit work queue blocks/waits, AbstractWork Not Runnable

1. Log a warning for work which blocks and/or waits
2. Make AbstractWork no longer extend Runnable, add javadoc explaining
importance of work completely quickly
3. Minor refactoring due to 2.

Change-Id: I211e4a9e68ee3ac5fa8e02d79b661068734035c7
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1220
Sonar-Qube: Jenkins <je...@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
Reviewed-by: Till Westmann <ti...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/3b5c3c62
Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/3b5c3c62
Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/3b5c3c62

Branch: refs/heads/master
Commit: 3b5c3c621eca6d68b6bafe6c53b8e16d96816706
Parents: 6277d15
Author: Michael Blow <mb...@apache.org>
Authored: Wed Sep 28 15:31:11 2016 -0400
Committer: Michael Blow <mb...@apache.org>
Committed: Wed Sep 28 13:43:16 2016 -0700

----------------------------------------------------------------------
 .../HyracksClientInterfaceRemoteProxy.java      |  9 +-
 .../control/cc/work/GetThreadDumpWork.java      | 16 ++--
 .../control/common/utils/ThreadDumpHelper.java  | 86 ++++++++++++++++++++
 .../control/common/work/AbstractWork.java       |  6 ++
 .../control/common/work/ThreadDumpWork.java     | 83 -------------------
 .../hyracks/control/common/work/WorkQueue.java  | 82 ++++++++++---------
 .../control/nc/NodeControllerService.java       |  8 +-
 .../hyracks/control/nc/task/ShutdownTask.java   | 66 +++++++++++++++
 .../hyracks/control/nc/task/ThreadDumpTask.java | 53 ++++++++++++
 .../control/nc/work/NodeThreadDumpWork.java     | 39 ---------
 .../hyracks/control/nc/work/ShutdownWork.java   | 67 ---------------
 11 files changed, 276 insertions(+), 239 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3b5c3c62/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/client/HyracksClientInterfaceRemoteProxy.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/client/HyracksClientInterfaceRemoteProxy.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/client/HyracksClientInterfaceRemoteProxy.java
index fda9cc3..f8c8512 100644
--- a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/client/HyracksClientInterfaceRemoteProxy.java
+++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/client/HyracksClientInterfaceRemoteProxy.java
@@ -36,6 +36,8 @@ import org.apache.hyracks.ipc.api.RPCInterface;
 import org.apache.hyracks.ipc.exceptions.IPCException;
 
 public class HyracksClientInterfaceRemoteProxy implements IHyracksClientInterface {
+    private static final int SHUTDOWN_CONNECTION_TIMEOUT_SECS = 30;
+
     private final IIPCHandle ipcHandle;
 
     private final RPCInterface rpci;
@@ -127,15 +129,16 @@ public class HyracksClientInterfaceRemoteProxy implements IHyracksClientInterfac
         HyracksClientInterfaceFunctions.ClusterShutdownFunction csdf =
                 new HyracksClientInterfaceFunctions.ClusterShutdownFunction(terminateNCService);
         rpci.call(ipcHandle, csdf);
+        int i = 0;
         // give the CC some time to do final settling after it returns our request
-        int seconds = 30;
-        while (ipcHandle.isConnected() && --seconds > 0) {
+        while (ipcHandle.isConnected() && i++ < SHUTDOWN_CONNECTION_TIMEOUT_SECS) {
             synchronized (this) {
                 wait(TimeUnit.SECONDS.toMillis(1));
             }
         }
         if (ipcHandle.isConnected()) {
-            throw new IPCException("CC refused to release connection after 30 seconds");
+            throw new IPCException("CC refused to release connection after " + SHUTDOWN_CONNECTION_TIMEOUT_SECS
+                    + " seconds");
         }
     }
 

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3b5c3c62/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/GetThreadDumpWork.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/GetThreadDumpWork.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/GetThreadDumpWork.java
index 7931cf8..889c828 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/GetThreadDumpWork.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/GetThreadDumpWork.java
@@ -27,11 +27,12 @@ import java.util.logging.Logger;
 
 import org.apache.hyracks.control.cc.ClusterControllerService;
 import org.apache.hyracks.control.cc.NodeControllerState;
+import org.apache.hyracks.control.common.utils.ThreadDumpHelper;
+import org.apache.hyracks.control.common.work.AbstractWork;
 import org.apache.hyracks.control.common.work.IResultCallback;
-import org.apache.hyracks.control.common.work.ThreadDumpWork;
 
-public class GetThreadDumpWork extends ThreadDumpWork {
-    private static final Logger LOGGER = Logger.getLogger(ThreadDumpWork.class.getName());
+public class GetThreadDumpWork extends AbstractWork {
+    private static final Logger LOGGER = Logger.getLogger(GetThreadDumpWork.class.getName());
     public static final int TIMEOUT_SECS = 60;
 
     private final ClusterControllerService ccs;
@@ -48,10 +49,15 @@ public class GetThreadDumpWork extends ThreadDumpWork {
     }
 
     @Override
-    protected void doRun() throws Exception {
+    public void run() {
         if (nodeId == null) {
             // null nodeId means the request is for the cluster controller
-            callback.setValue(takeDump(ManagementFactory.getThreadMXBean()));
+            try {
+                callback.setValue(ThreadDumpHelper.takeDumpJSON(ManagementFactory.getThreadMXBean()));
+            } catch (Exception e) {
+                LOGGER.log(Level.WARNING, "Exception taking CC thread dump", e);
+                callback.setException(e);
+            }
         } else {
             final NodeControllerState ncState = ccs.getNodeMap().get(nodeId);
             if (ncState == null) {

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3b5c3c62/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/utils/ThreadDumpHelper.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/utils/ThreadDumpHelper.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/utils/ThreadDumpHelper.java
new file mode 100644
index 0000000..eacb9e0
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/utils/ThreadDumpHelper.java
@@ -0,0 +1,86 @@
+/*
+ * 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.hyracks.control.common.utils;
+
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class ThreadDumpHelper {
+
+    private ThreadDumpHelper() {
+    }
+
+    public static String takeDumpJSON(ThreadMXBean threadMXBean) throws JSONException {
+        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(true, true);
+        List<Map<String, Object>> threads = new ArrayList<>();
+
+        for (ThreadInfo thread : threadInfos) {
+            Map<String, Object> threadMap = new HashMap<>();
+            threadMap.put("name", thread.getThreadName());
+            threadMap.put("id", thread.getThreadId());
+            threadMap.put("state", thread.getThreadState().name());
+            List<String> stacktrace = new ArrayList<>();
+            for (StackTraceElement element : thread.getStackTrace()) {
+                stacktrace.add(element.toString());
+            }
+            threadMap.put("stack", stacktrace);
+
+            if (thread.getLockName() != null) {
+                threadMap.put("lock_name", thread.getLockName());
+            }
+            if (thread.getLockOwnerId() != -1) {
+                threadMap.put("lock_owner_id", thread.getLockOwnerId());
+            }
+            if (thread.getBlockedTime() > 0) {
+                threadMap.put("blocked_time", thread.getBlockedTime());
+            }
+            if (thread.getBlockedCount() > 0) {
+                threadMap.put("blocked_count", thread.getBlockedCount());
+            }
+            if (thread.getLockedMonitors().length > 0) {
+                threadMap.put("locked_monitors", thread.getLockedMonitors());
+            }
+            if (thread.getLockedSynchronizers().length > 0) {
+                threadMap.put("locked_synchronizers", thread.getLockedSynchronizers());
+            }
+            threads.add(threadMap);
+        }
+        JSONObject json = new JSONObject();
+        json.put("date", new Date());
+        json.put("threads", threads);
+
+        long [] deadlockedThreads = threadMXBean.findDeadlockedThreads();
+        long [] monitorDeadlockedThreads = threadMXBean.findMonitorDeadlockedThreads();
+        if (deadlockedThreads != null && deadlockedThreads.length > 0) {
+            json.put("deadlocked_thread_ids", deadlockedThreads);
+        }
+        if (monitorDeadlockedThreads != null && monitorDeadlockedThreads.length > 0) {
+            json.put("monitor_deadlocked_thread_ids", monitorDeadlockedThreads);
+        }
+        return json.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3b5c3c62/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/AbstractWork.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/AbstractWork.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/AbstractWork.java
index 9376370..076dd66 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/AbstractWork.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/AbstractWork.java
@@ -31,6 +31,12 @@ public abstract class AbstractWork implements Runnable {
         return className.substring(className.lastIndexOf('.') + 1, endIndex);
     }
 
+    /**
+     * run is executed on a single thread that services the work queue. As a result run should never wait or block as
+     * this will delay processing for the whole queue.
+     */
+    public abstract void run();
+
     @Override
     public String toString() {
         return getName();

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3b5c3c62/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/ThreadDumpWork.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/ThreadDumpWork.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/ThreadDumpWork.java
deleted file mode 100644
index bf1965d..0000000
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/ThreadDumpWork.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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.hyracks.control.common.work;
-
-import java.lang.management.ThreadInfo;
-import java.lang.management.ThreadMXBean;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-public abstract class ThreadDumpWork extends SynchronizableWork {
-
-    protected String takeDump(ThreadMXBean threadMXBean) throws JSONException {
-        ThreadInfo [] threadInfos = threadMXBean.dumpAllThreads(true, true);
-        List<Map<String, Object>> threads = new ArrayList<>();
-
-        for (ThreadInfo thread : threadInfos) {
-            Map<String, Object> threadMap = new HashMap<>();
-            threadMap.put("name", thread.getThreadName());
-            threadMap.put("id", thread.getThreadId());
-            threadMap.put("state", thread.getThreadState().name());
-            List<String> stacktrace = new ArrayList<>();
-            for (StackTraceElement element : thread.getStackTrace()) {
-                stacktrace.add(element.toString());
-            }
-            threadMap.put("stack", stacktrace);
-
-            if (thread.getLockName() != null) {
-                threadMap.put("lock_name", thread.getLockName());
-            }
-            if (thread.getLockOwnerId() != -1) {
-                threadMap.put("lock_owner_id", thread.getLockOwnerId());
-            }
-            if (thread.getBlockedTime() > 0) {
-                threadMap.put("blocked_time", thread.getBlockedTime());
-            }
-            if (thread.getBlockedCount() > 0) {
-                threadMap.put("blocked_count", thread.getBlockedCount());
-            }
-            if (thread.getLockedMonitors().length > 0) {
-                threadMap.put("locked_monitors", thread.getLockedMonitors());
-            }
-            if (thread.getLockedSynchronizers().length > 0) {
-                threadMap.put("locked_synchronizers", thread.getLockedSynchronizers());
-            }
-            threads.add(threadMap);
-        }
-        JSONObject json = new JSONObject();
-        json.put("date", new Date());
-        json.put("threads", threads);
-
-        long [] deadlockedThreads = threadMXBean.findDeadlockedThreads();
-        long [] monitorDeadlockedThreads = threadMXBean.findMonitorDeadlockedThreads();
-        if (deadlockedThreads != null && deadlockedThreads.length > 0) {
-            json.put("deadlocked_thread_ids", deadlockedThreads);
-        }
-        if (monitorDeadlockedThreads != null && monitorDeadlockedThreads.length > 0) {
-            json.put("monitor_deadlocked_thread_ids", monitorDeadlockedThreads);
-        }
-        return json.toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3b5c3c62/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/WorkQueue.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/WorkQueue.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/WorkQueue.java
index fe0821f..f1b00ab 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/WorkQueue.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/work/WorkQueue.java
@@ -18,8 +18,10 @@
  */
 package org.apache.hyracks.control.common.work;
 
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
 import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.Semaphore;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -33,11 +35,11 @@ public class WorkQueue {
 
     private final LinkedBlockingQueue<AbstractWork> queue;
     private final WorkerThread thread;
-    private final Semaphore stopSemaphore;
     private boolean stopped;
     private AtomicInteger enqueueCount;
     private AtomicInteger dequeueCount;
     private int threadPriority = Thread.MAX_PRIORITY;
+    private final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
 
     public WorkQueue(String id, int threadPriority) {
         if (threadPriority != Thread.MAX_PRIORITY && threadPriority != Thread.NORM_PRIORITY
@@ -47,21 +49,14 @@ public class WorkQueue {
         this.threadPriority = threadPriority;
         queue = new LinkedBlockingQueue<>();
         thread = new WorkerThread(id);
-        stopSemaphore = new Semaphore(1);
         stopped = true;
-        if(DEBUG) {
+        if (DEBUG) {
             enqueueCount = new AtomicInteger(0);
             dequeueCount = new AtomicInteger(0);
         }
     }
 
     public void start() throws HyracksException {
-        try {
-            stopSemaphore.acquire();
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-            throw new HyracksException(e);
-        }
         if (DEBUG) {
             enqueueCount.set(0);
             dequeueCount.set(0);
@@ -76,7 +71,7 @@ public class WorkQueue {
         }
         thread.interrupt();
         try {
-            stopSemaphore.acquire();
+            thread.join();
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
             throw new HyracksException(e);
@@ -107,35 +102,46 @@ public class WorkQueue {
 
         @Override
         public void run() {
-            try {
-                AbstractWork r;
-                while (true) {
-                    synchronized (WorkQueue.this) {
-                        if (stopped) {
-                            return;
-                        }
-                    }
-                    try {
-                        r = queue.take();
-                    } catch (InterruptedException e) { // NOSONAR: aborting the thread
-                        break;
-                    }
-                    if (DEBUG) {
-                        LOGGER.log(Level.FINEST,
-                                "Dequeue (" + WorkQueue.this.hashCode() + "): " + dequeueCount.incrementAndGet() + "/"
-                                        + enqueueCount);
-                    }
-                    try {
-                        if (LOGGER.isLoggable(r.logLevel())) {
-                            LOGGER.log(r.logLevel(), "Executing: " + r);
-                        }
-                        r.run();
-                    } catch (Exception e) {
-                        LOGGER.log(Level.WARNING, "Exception while executing " + r, e);
+            AbstractWork r;
+            while (true) {
+                synchronized (WorkQueue.this) {
+                    if (stopped) {
+                        return;
                     }
                 }
-            } finally {
-                stopSemaphore.release();
+                try {
+                    r = queue.take();
+                } catch (InterruptedException e) { // NOSONAR: aborting the thread
+                    break;
+                }
+                if (DEBUG) {
+                    LOGGER.log(Level.FINEST,
+                            "Dequeue (" + WorkQueue.this.hashCode() + "): " + dequeueCount.incrementAndGet() + "/"
+                                    + enqueueCount);
+                }
+                if (LOGGER.isLoggable(r.logLevel())) {
+                    LOGGER.log(r.logLevel(), "Executing: " + r);
+                }
+                ThreadInfo before = threadMXBean.getThreadInfo(thread.getId());
+                try {
+                    r.run();
+                } catch (Exception e) {
+                    LOGGER.log(Level.WARNING, "Exception while executing " + r, e);
+                } finally {
+                    auditWaitsAndBlocks(r, before);
+                }
+            }
+        }
+
+        protected void auditWaitsAndBlocks(AbstractWork r, ThreadInfo before) {
+            ThreadInfo after = threadMXBean.getThreadInfo(thread.getId());
+            final long waitedDelta = after.getWaitedCount() - before.getWaitedCount();
+            final long blockedDelta = after.getBlockedCount() - before.getBlockedCount();
+            if (waitedDelta > 0 || blockedDelta > 0) {
+                LOGGER.warning("Work " + r + " waited " + waitedDelta + " times (~"
+                        + (after.getWaitedTime() - before.getWaitedTime()) + "ms), blocked " + blockedDelta
+                        + " times (~" + (after.getBlockedTime() - before.getBlockedTime()) + "ms)"
+                );
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3b5c3c62/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NodeControllerService.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NodeControllerService.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NodeControllerService.java
index d2d4811..ed46b53 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NodeControllerService.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NodeControllerService.java
@@ -85,10 +85,10 @@ import org.apache.hyracks.control.nc.work.BuildJobProfilesWork;
 import org.apache.hyracks.control.nc.work.CleanupJobletWork;
 import org.apache.hyracks.control.nc.work.DeployBinaryWork;
 import org.apache.hyracks.control.nc.work.ReportPartitionAvailabilityWork;
-import org.apache.hyracks.control.nc.work.ShutdownWork;
+import org.apache.hyracks.control.nc.task.ShutdownTask;
 import org.apache.hyracks.control.nc.work.StartTasksWork;
 import org.apache.hyracks.control.nc.work.StateDumpWork;
-import org.apache.hyracks.control.nc.work.NodeThreadDumpWork;
+import org.apache.hyracks.control.nc.task.ThreadDumpTask;
 import org.apache.hyracks.control.nc.work.UnDeployBinaryWork;
 import org.apache.hyracks.ipc.api.IIPCHandle;
 import org.apache.hyracks.ipc.api.IIPCI;
@@ -573,12 +573,12 @@ public class NodeControllerService implements IControllerService {
 
                 case SHUTDOWN_REQUEST:
                     final CCNCFunctions.ShutdownRequestFunction sdrf = (CCNCFunctions.ShutdownRequestFunction) fn;
-                    executor.submit(new ShutdownWork(NodeControllerService.this, sdrf.isTerminateNCService()));
+                    executor.submit(new ShutdownTask(NodeControllerService.this, sdrf.isTerminateNCService()));
                     return;
 
                 case THREAD_DUMP_REQUEST:
                     final CCNCFunctions.ThreadDumpRequestFunction tdrf = (CCNCFunctions.ThreadDumpRequestFunction) fn;
-                    executor.submit(new NodeThreadDumpWork(NodeControllerService.this, tdrf.getRequestId()));
+                    executor.submit(new ThreadDumpTask(NodeControllerService.this, tdrf.getRequestId()));
                     return;
 
                 default:

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3b5c3c62/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/task/ShutdownTask.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/task/ShutdownTask.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/task/ShutdownTask.java
new file mode 100644
index 0000000..cdbd4ad
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/task/ShutdownTask.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.hyracks.control.nc.task;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.hyracks.control.common.base.IClusterController;
+import org.apache.hyracks.control.nc.NodeControllerService;
+
+public class ShutdownTask implements Runnable {
+    private static final Logger LOGGER = Logger.getLogger(ShutdownTask.class.getName());
+    private final NodeControllerService ncs;
+    private final boolean terminateNCService;
+
+    public ShutdownTask(NodeControllerService ncs, boolean terminateNCService) {
+        this.ncs = ncs;
+        this.terminateNCService = terminateNCService;
+    }
+
+    @Override
+    public void run() {
+        IClusterController ccs = ncs.getClusterController();
+        try {
+            ccs.notifyShutdown(ncs.getId());
+        } catch (Exception e) {
+            LOGGER.log(Level.WARNING, "Exception notifying CC of shutdown acknowledgment", e);
+            // proceed with shutdown
+        }
+
+        LOGGER.info("JVM Exiting.. Bye!");
+        //run the shutdown in a new thread, so we don't block this last work task
+        Thread t = new Thread("NC " + ncs.getId() + " Shutdown") {
+            @Override
+            public void run() {
+                try {
+                    ncs.stop();
+                } catch (Exception e) {
+                    LOGGER.log(Level.SEVERE, "Exception stopping node controller service", e);
+                } finally {
+                    Runtime rt = Runtime.getRuntime();
+                    rt.exit(terminateNCService ? 99 : 0);
+                }
+            }
+        };
+        t.start();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3b5c3c62/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/task/ThreadDumpTask.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/task/ThreadDumpTask.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/task/ThreadDumpTask.java
new file mode 100644
index 0000000..68d9223
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/task/ThreadDumpTask.java
@@ -0,0 +1,53 @@
+/*
+ * 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.hyracks.control.nc.task;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.hyracks.control.common.utils.ThreadDumpHelper;
+import org.apache.hyracks.control.nc.NodeControllerService;
+
+public class ThreadDumpTask implements Runnable {
+    private static final Logger LOGGER = Logger.getLogger(ThreadDumpTask.class.getName());
+    private final NodeControllerService ncs;
+    private final String requestId;
+
+    public ThreadDumpTask(NodeControllerService ncs, String requestId) {
+        this.ncs = ncs;
+        this.requestId = requestId;
+    }
+
+    @Override
+    public void run() {
+        String result;
+        try {
+            result = ThreadDumpHelper.takeDumpJSON(ncs.getThreadMXBean());
+        } catch (Exception e) {
+            LOGGER.log(Level.WARNING, "Exception taking thread dump", e);
+            result = null;
+        }
+        try {
+            ncs.getClusterController().notifyThreadDump(
+                    ncs.getApplicationContext().getNodeId(), requestId, result);
+        } catch (Exception e) {
+            LOGGER.log(Level.WARNING, "Exception sending thread dump to CC", e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3b5c3c62/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/work/NodeThreadDumpWork.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/work/NodeThreadDumpWork.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/work/NodeThreadDumpWork.java
deleted file mode 100644
index 85233b2..0000000
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/work/NodeThreadDumpWork.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.hyracks.control.nc.work;
-
-import org.apache.hyracks.control.common.work.ThreadDumpWork;
-import org.apache.hyracks.control.nc.NodeControllerService;
-
-public class NodeThreadDumpWork extends ThreadDumpWork {
-    private final NodeControllerService ncs;
-    private final String requestId;
-
-    public NodeThreadDumpWork(NodeControllerService ncs, String requestId) {
-        this.ncs = ncs;
-        this.requestId = requestId;
-    }
-
-    @Override
-    protected void doRun() throws Exception {
-        final String result = takeDump(ncs.getThreadMXBean());
-        ncs.getClusterController().notifyThreadDump(
-                ncs.getApplicationContext().getNodeId(), requestId, result);
-    }
-}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3b5c3c62/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/work/ShutdownWork.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/work/ShutdownWork.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/work/ShutdownWork.java
deleted file mode 100644
index c195c98..0000000
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/work/ShutdownWork.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.hyracks.control.nc.work;
-
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.apache.hyracks.control.common.base.IClusterController;
-import org.apache.hyracks.control.common.work.AbstractWork;
-import org.apache.hyracks.control.nc.NodeControllerService;
-
-public class ShutdownWork extends AbstractWork {
-    private static final Logger LOGGER = Logger.getLogger(ShutdownWork.class.getName());
-    private final NodeControllerService ncs;
-    private final boolean terminateNCService;
-
-    public ShutdownWork(NodeControllerService ncs, boolean terminateNCService) {
-        this.ncs = ncs;
-        this.terminateNCService = terminateNCService;
-    }
-
-    @Override
-    public void run() {
-        IClusterController ccs = ncs.getClusterController();
-        try {
-            ccs.notifyShutdown(ncs.getId());
-        } catch (Exception e) {
-            LOGGER.log(Level.WARNING, "Exception notifying CC of shutdown acknowledgment", e);
-            // proceed with shutdown
-        }
-
-        LOGGER.info("JVM Exiting.. Bye!");
-        //run the shutdown in a new thread, so we don't block this last work task
-        Thread t = new Thread("NC " + ncs.getId() + " Shutdown") {
-            @Override
-            public void run() {
-                try {
-                    ncs.stop();
-                } catch (Exception e) {
-                    LOGGER.log(Level.SEVERE, "Exception stopping node controller service", e);
-                } finally {
-                    Runtime rt = Runtime.getRuntime();
-                    rt.exit(terminateNCService ? 99 : 0);
-                }
-            }
-        };
-        t.start();
-    }
-
-}