{"action":"created","comment":{"url":"https://api.github.com/repos/apache/storm/pulls/comments/77457645","id":77457645,"diff_hunk":"@@ -0,0 +1,768 @@\n+/**\n+ * Licensed to the Apache Software Foundation (ASF) under one\n+ * or more contributor license agreements.  See the NOTICE file\n+ * distributed with this work for additional information\n+ * regarding copyright ownership.  The ASF licenses this file\n+ * to you under the Apache License, Version 2.0 (the\n+ * \"License\"); you may not use this file except in compliance\n+ * with the License.  You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+package org.apache.storm.daemon.supervisor;\n+\n+import java.io.IOException;\n+import java.util.Collections;\n+import java.util.HashMap;\n+import java.util.HashSet;\n+import java.util.Iterator;\n+import java.util.Map;\n+import java.util.Set;\n+import java.util.concurrent.Future;\n+import java.util.concurrent.TimeUnit;\n+import java.util.concurrent.TimeoutException;\n+import java.util.concurrent.atomic.AtomicReference;\n+\n+import org.apache.storm.Config;\n+import org.apache.storm.cluster.IStormClusterState;\n+import org.apache.storm.generated.ExecutorInfo;\n+import org.apache.storm.generated.LSWorkerHeartbeat;\n+import org.apache.storm.generated.LocalAssignment;\n+import org.apache.storm.generated.ProfileAction;\n+import org.apache.storm.generated.ProfileRequest;\n+import org.apache.storm.localizer.ILocalizer;\n+import org.apache.storm.scheduler.ISupervisor;\n+import org.apache.storm.utils.LocalState;\n+import org.apache.storm.utils.Time;\n+import org.apache.storm.utils.Utils;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+public class Slot extends Thread implements AutoCloseable {\n+    private static final Logger LOG = LoggerFactory.getLogger(Slot.class);\n+    \n+    static enum MachineState {\n+        EMPTY,\n+        RUNNING,\n+        WAITING_FOR_WORKER_START,\n+        KILL_AND_RELAUNCH,\n+        KILL,\n+        WAITING_FOR_BASIC_LOCALIZATION,\n+        WAITING_FOR_BLOB_LOCALIZATION;\n+    };\n+    \n+    static class StaticState {\n+        public final ILocalizer localizer;\n+        public final long hbTimeoutMs;\n+        public final long firstHbTimeoutMs;\n+        public final long killSleepMs;\n+        public final long monitorFreqMs;\n+        public final ContainerLauncher containerLauncher;\n+        public final int port;\n+        public final String host;\n+        public final ISupervisor iSupervisor;\n+        public final LocalState localState;\n+        \n+        StaticState(ILocalizer localizer, long hbTimeoutMs, long firstHbTimeoutMs,\n+                long killSleepMs, long monitorFreqMs,\n+                ContainerLauncher containerLauncher, String host, int port,\n+                ISupervisor iSupervisor, LocalState localState) {\n+            this.localizer = localizer;\n+            this.hbTimeoutMs = hbTimeoutMs;\n+            this.firstHbTimeoutMs = firstHbTimeoutMs;\n+            this.containerLauncher = containerLauncher;\n+            this.killSleepMs = killSleepMs;\n+            this.monitorFreqMs = monitorFreqMs;\n+            this.host = host;\n+            this.port = port;\n+            this.iSupervisor = iSupervisor;\n+            this.localState = localState;\n+        }\n+    }\n+    \n+    static class DynamicState {\n+        public final MachineState state;\n+        public final LocalAssignment newAssignment;\n+        public final LocalAssignment currentAssignment;\n+        public final Container container;\n+        public final LocalAssignment pendingLocalization;\n+        public final Future<Void> pendingDownload;\n+        public final Set<TopoProfileAction> profileActions;\n+        public final Set<TopoProfileAction> pendingStopProfileActions;\n+        \n+        /**\n+         * The last time that WAITING_FOR_WORKER_START, KILL, or KILL_AND_RELAUNCH were entered into.\n+         */\n+        public final long startTime;\n+        \n+        public DynamicState(final LocalAssignment currentAssignment, Container container, final LocalAssignment newAssignment) {\n+            this.currentAssignment = currentAssignment;\n+            this.container = container;\n+            if ((currentAssignment == null) ^ (container == null)) {\n+                throw new IllegalArgumentException(\"Container and current assignment must both be null, or neither can be null\");\n+            }\n+            \n+            if (currentAssignment == null) {\n+                state = MachineState.EMPTY;\n+            } else {\n+                state = MachineState.RUNNING;\n+            }\n+            \n+            this.startTime = System.currentTimeMillis();\n+            this.newAssignment = newAssignment;\n+            this.pendingLocalization = null;\n+            this.pendingDownload = null;\n+            this.profileActions = new HashSet<>();\n+            this.pendingStopProfileActions = new HashSet<>();\n+        }\n+        \n+        public DynamicState(final MachineState state, final LocalAssignment newAssignment,\n+                final Container container, final LocalAssignment currentAssignment,\n+                final LocalAssignment pendingLocalization, final long startTime,\n+                final Future<Void> pendingDownload, final Set<TopoProfileAction> profileActions, \n+                final Set<TopoProfileAction> pendingStopProfileActions) {\n+            this.state = state;\n+            this.newAssignment = newAssignment;\n+            this.currentAssignment = currentAssignment;\n+            this.container = container;\n+            this.pendingLocalization = pendingLocalization;\n+            this.startTime = startTime;\n+            this.pendingDownload = pendingDownload;\n+            this.profileActions = profileActions;\n+            this.pendingStopProfileActions = pendingStopProfileActions;\n+        }\n+        \n+        public String toString() {\n+            StringBuffer sb = new StringBuffer();\n+            sb.append(state);\n+            if (state == MachineState.WAITING_FOR_WORKER_START ||\n+                state == MachineState.KILL ||\n+                state == MachineState.KILL_AND_RELAUNCH) {\n+                sb.append(\" msInState: \");\n+                sb.append(Time.currentTimeMillis() - startTime);\n+            }\n+            if (container != null) {\n+                sb.append(\" container: \");\n+                sb.append(container);\n+            }\n+            return sb.toString();\n+        }\n+\n+        public DynamicState withNewAssignment(LocalAssignment newAssignment) {\n+            return new DynamicState(this.state, newAssignment,\n+                    this.container, this.currentAssignment,\n+                    this.pendingLocalization, this.startTime,\n+                    this.pendingDownload, this.profileActions,\n+                    this.pendingStopProfileActions);\n+        }\n+        \n+        public DynamicState withPendingLocalization(LocalAssignment pendingLocalization, Future<Void> pendingDownload) {\n+            return new DynamicState(this.state, this.newAssignment,\n+                    this.container, this.currentAssignment,\n+                    pendingLocalization, this.startTime,\n+                    pendingDownload, this.profileActions,\n+                    this.pendingStopProfileActions);\n+        }\n+        \n+        public DynamicState withPendingLocalization(Future<Void> pendingDownload) {\n+            return new DynamicState(this.state, this.newAssignment,\n+                    this.container, this.currentAssignment,\n+                    this.pendingLocalization, this.startTime,\n+                    pendingDownload, this.profileActions,\n+                    this.pendingStopProfileActions);\n+        }\n+        \n+        public DynamicState withState(final MachineState state) {\n+            long newStartTime = this.startTime;\n+            if (state == MachineState.KILL ||\n+                    state == MachineState.KILL_AND_RELAUNCH ||\n+                    state == MachineState.WAITING_FOR_WORKER_START) {\n+                newStartTime = Time.currentTimeMillis();\n+            }\n+            return new DynamicState(state, this.newAssignment,\n+                    this.container, this.currentAssignment,\n+                    this.pendingLocalization, newStartTime,\n+                    this.pendingDownload, this.profileActions,\n+                    this.pendingStopProfileActions);\n+        }\n+\n+        public DynamicState withCurrentAssignment(final Container container, final LocalAssignment currentAssignment) {\n+            return new DynamicState(this.state, this.newAssignment,\n+                    container, currentAssignment,\n+                    this.pendingLocalization, this.startTime,\n+                    this.pendingDownload, this.profileActions,\n+                    this.pendingStopProfileActions);\n+        }\n+\n+        public DynamicState withProfileActions(Set<TopoProfileAction> profileActions, Set<TopoProfileAction> pendingStopProfileActions) {\n+            return new DynamicState(this.state, this.newAssignment,\n+                    this.container, this.currentAssignment,\n+                    this.pendingLocalization, this.startTime,\n+                    this.pendingDownload, profileActions,\n+                    pendingStopProfileActions);\n+        }\n+    };\n+    \n+    static class TopoProfileAction {\n+        public final String topoId;\n+        public final ProfileRequest request;\n+        \n+        public TopoProfileAction(String topoId, ProfileRequest request) {\n+            this.topoId = topoId;\n+            this.request = request;\n+        }\n+        \n+        @Override\n+        public int hashCode() {\n+            return (37 * topoId.hashCode()) + request.hashCode(); \n+        }\n+        \n+        @Override\n+        public boolean equals(Object other) {\n+            if (!(other instanceof TopoProfileAction)) {\n+                return false;\n+            }\n+            TopoProfileAction o = (TopoProfileAction) other;\n+            return topoId.equals(o.topoId) && request.equals(o.request);\n+        }\n+        \n+        @Override\n+        public String toString() {\n+            return \"{ \"+topoId + \": \" + request + \" }\";\n+        }\n+    }\n+    \n+    static boolean equivalent(LocalAssignment a, LocalAssignment b) {\n+        if (a == null && b == null) {\n+            return true;\n+        } if (a != null && b != null) {\n+            if (a.get_topology_id().equals(b.get_topology_id())) {\n+                Set<ExecutorInfo> aexec = new HashSet<>(a.get_executors());\n+                Set<ExecutorInfo> bexec = new HashSet<>(b.get_executors());\n+                if (aexec.equals(bexec)) {\n+                    boolean aHasResources = a.is_set_resources();\n+                    boolean bHasResources = b.is_set_resources();\n+                    if (!aHasResources && !bHasResources) {\n+                        return true;\n+                    } else if (aHasResources && bHasResources) {\n+                        if (a.get_resources().equals(b.get_resources())) {\n+                            return true;\n+                        }\n+                    }\n+                }\n+            }\n+        }\n+        return false;\n+    }\n+    \n+    static DynamicState stateMachineStep(DynamicState dynamicState, StaticState staticState) throws Exception {\n+        LOG.debug(\"STATE {}\", dynamicState.state);\n+        switch (dynamicState.state) {\n+            case EMPTY:\n+                return handleEmpty(dynamicState, staticState);\n+            case RUNNING:\n+                return handleRunning(dynamicState, staticState);\n+            case WAITING_FOR_WORKER_START:\n+                return handleWaitingForWorkerStart(dynamicState, staticState);\n+            case KILL_AND_RELAUNCH:\n+                return handleKillAndRelaunch(dynamicState, staticState);\n+            case KILL:\n+                return handleKill(dynamicState, staticState);\n+            case WAITING_FOR_BASIC_LOCALIZATION:\n+                return handleWaitingForBasicLocalization(dynamicState, staticState);\n+            case WAITING_FOR_BLOB_LOCALIZATION:\n+                return handleWaitingForBlobLocalization(dynamicState, staticState);\n+            default:\n+                throw new IllegalStateException(\"Code not ready to handle a state of \"+dynamicState.state);\n+        }\n+    }\n+    \n+    /**\n+     * Prepare for a new assignment my downloading new required blobs, or going to empty if there is nothing to download.\n+     * PRECONDITION: The slot should be empty\n+     * @param dynamicState current state\n+     * @param staticState static data\n+     * @return the next state\n+     * @throws IOException on any error\n+     */\n+    static DynamicState prepareForNewAssignmentOnEmptySlot(DynamicState dynamicState, StaticState staticState) throws IOException {\n+        assert(dynamicState.container == null);\n+        \n+        if (dynamicState.newAssignment == null) {\n+            return dynamicState.withState(MachineState.EMPTY);\n+        }\n+        Future<Void> pendingDownload = staticState.localizer.requestDownloadBaseTopologyBlobs(dynamicState.newAssignment.get_topology_id(), staticState.port);\n+        return dynamicState.withPendingLocalization(dynamicState.newAssignment, pendingDownload).withState(MachineState.WAITING_FOR_BASIC_LOCALIZATION);\n+    }\n+    \n+    /**\n+     * Kill the current container and start downloading what the new assignment needs, if there is a new assignment\n+     * PRECONDITION: container != null\n+     * @param dynamicState current state\n+     * @param staticState static data\n+     * @return the next state\n+     * @throws Exception \n+     */\n+    static DynamicState killContainerForChangedAssignment(DynamicState dynamicState, StaticState staticState) throws Exception {\n+        assert(dynamicState.container != null);\n+        \n+        staticState.iSupervisor.killedWorker(staticState.port);\n+        dynamicState.container.kill();\n+        Future<Void> pendingDownload = null;\n+        if (dynamicState.newAssignment != null) {\n+            pendingDownload = staticState.localizer.requestDownloadBaseTopologyBlobs(dynamicState.newAssignment.get_topology_id(), staticState.port);\n+        }\n+        Time.sleep(staticState.killSleepMs);\n+        return dynamicState.withPendingLocalization(dynamicState.newAssignment, pendingDownload).withState(MachineState.KILL);\n+    }\n+    \n+    /**\n+     * Kill the current container and relaunch it.  (Something odd happened)\n+     * PRECONDITION: container != null\n+     * @param dynamicState current state\n+     * @param staticState static data\n+     * @return the next state\n+     * @throws Exception \n+     */\n+    static DynamicState killAndRelaunchContainer(DynamicState dynamicState, StaticState staticState) throws Exception {\n+        assert(dynamicState.container != null);\n+        \n+        dynamicState.container.kill();\n+        Time.sleep(staticState.killSleepMs);\n+        \n+        //any stop profile actions that hadn't timed out yet, we should restart after the worker is running again.\n+        HashSet<TopoProfileAction> mod = new HashSet<>(dynamicState.profileActions);\n+        mod.addAll(dynamicState.pendingStopProfileActions);\n+        return dynamicState.withState(MachineState.KILL_AND_RELAUNCH).withProfileActions(mod, Collections.<TopoProfileAction> emptySet());\n+    }\n+    \n+    /**\n+     * Clean up a container\n+     * PRECONDITION: All of the processes have died.\n+     * @param dynamicState current state\n+     * @param staticState static data\n+     * @param nextState the next MachineState to go to.\n+     * @return the next state.\n+     */\n+    static DynamicState cleanupCurrentContainer(DynamicState dynamicState, StaticState staticState, MachineState nextState) throws Exception {\n+        assert(dynamicState.container != null);\n+        assert(dynamicState.currentAssignment != null);\n+        \n+        dynamicState.container.cleanUp();\n+        staticState.localizer.releaseSlotFor(dynamicState.currentAssignment.get_topology_id(), staticState.port);\n+        DynamicState ret = dynamicState.withCurrentAssignment(null, null);\n+        if (nextState != null) {\n+            ret = ret.withState(nextState);\n+        }\n+        return ret;\n+    }\n+    \n+    /**\n+     * State Transitions for WAITING_FOR_BLOB_LOCALIZATION state.\n+     * PRECONDITION: neither pendingLocalization nor pendingDownload is null.\n+     * PRECONDITION: The slot should be empty\n+     * @param dynamicState current state\n+     * @param staticState static data\n+     * @return the next state\n+     * @throws Exception on any error\n+     */\n+    static DynamicState handleWaitingForBlobLocalization(DynamicState dynamicState, StaticState staticState) throws Exception {\n+        assert(dynamicState.pendingLocalization != null);\n+        assert(dynamicState.pendingDownload != null);\n+        assert(dynamicState.container == null);\n+        \n+        try {\n+            dynamicState.pendingDownload.get(1000, TimeUnit.MILLISECONDS);\n+            //Downloading of all blobs finished.\n+            if (!equivalent(dynamicState.newAssignment, dynamicState.pendingLocalization)) {\n+                //Scheduling changed\n+                staticState.localizer.releaseSlotFor(dynamicState.pendingLocalization.get_topology_id(), staticState.port);\n+                return prepareForNewAssignmentOnEmptySlot(dynamicState, staticState);\n+            }\n+            Container c = staticState.containerLauncher.launchContainer(staticState.port, dynamicState.pendingLocalization, staticState.localState);\n+            return dynamicState.withCurrentAssignment(c, dynamicState.pendingLocalization).withState(MachineState.WAITING_FOR_WORKER_START).withPendingLocalization(null, null);\n+        } catch (TimeoutException e) {\n+            //We waited for 1 second loop around and try again....\n+            return dynamicState;\n+        }\n+    }\n+    \n+    /**\n+     * State Transitions for WAITING_FOR_BASIC_LOCALIZATION state.\n+     * PRECONDITION: neither pendingLocalization nor pendingDownload is null.\n+     * PRECONDITION: The slot should be empty\n+     * @param dynamicState current state\n+     * @param staticState static data\n+     * @return the next state\n+     * @throws Exception on any error\n+     */\n+    static DynamicState handleWaitingForBasicLocalization(DynamicState dynamicState, StaticState staticState) throws Exception {\n+        assert(dynamicState.pendingLocalization != null);\n+        assert(dynamicState.pendingDownload != null);\n+        assert(dynamicState.container == null);\n+        \n+        //Ignore changes to scheduling while downloading the topology code\n+        try {\n+            dynamicState.pendingDownload.get(1000, TimeUnit.MILLISECONDS);\n+            Future<Void> pendingDownload = staticState.localizer.requestDownloadTopologyBlobs(dynamicState.pendingLocalization.get_topology_id(), staticState.port);\n+            return dynamicState.withPendingLocalization(pendingDownload).withState(MachineState.WAITING_FOR_BLOB_LOCALIZATION);\n+        } catch (TimeoutException e) {\n+            return dynamicState;\n+        }\n+    }\n+\n+    /**\n+     * State Transitions for KILL state.\n+     * PRECONDITION: container.kill() was called\n+     * PRECONDITION: container != null && currentAssignment != null\n+     * @param dynamicState current state\n+     * @param staticState static data\n+     * @return the next state\n+     * @throws Exception on any error\n+     */\n+    static DynamicState handleKill(DynamicState dynamicState, StaticState staticState) throws Exception {\n+        assert(dynamicState.container != null);\n+        assert(dynamicState.currentAssignment != null);\n+        \n+        if (dynamicState.container.areAllProcessesDead()) {\n+            LOG.warn(\"SLOT {} all processes are dead...\", staticState.port);\n+            return cleanupCurrentContainer(dynamicState, staticState, \n+                    dynamicState.pendingLocalization == null ? MachineState.EMPTY : MachineState.WAITING_FOR_BASIC_LOCALIZATION);\n+        }\n+\n+        LOG.warn(\"SLOT {} force kill and wait...\", staticState.port);\n+        dynamicState.container.forceKill();\n+        Time.sleep(staticState.killSleepMs);\n+        return dynamicState;\n+    }\n+\n+    /**\n+     * State Transitions for KILL_AND_RELAUNCH state.\n+     * PRECONDITION: container.kill() was called\n+     * PRECONDITION: container != null && currentAssignment != null\n+     * @param dynamicState current state\n+     * @param staticState static data\n+     * @return the next state\n+     * @throws Exception on any error\n+     */\n+    static DynamicState handleKillAndRelaunch(DynamicState dynamicState, StaticState staticState) throws Exception {\n+        assert(dynamicState.container != null);\n+        assert(dynamicState.currentAssignment != null);\n+        \n+        if (dynamicState.container.areAllProcessesDead()) {\n+            if (equivalent(dynamicState.newAssignment, dynamicState.currentAssignment)) {\n+                dynamicState.container.cleanUpForRestart();\n+                dynamicState.container.relaunch();\n+                return dynamicState.withState(MachineState.WAITING_FOR_WORKER_START);\n+            }\n+            //Scheduling changed after we killed all of the processes\n+            return prepareForNewAssignmentOnEmptySlot(cleanupCurrentContainer(dynamicState, staticState, null), staticState);\n+        }\n+        //The child processes typically exit in < 1 sec.  If 2 mins later they are still around something is wrong\n+        if ((Time.currentTimeMillis() - dynamicState.startTime) > 120000) {\n+            throw new RuntimeException(\"Not all processes in \" + dynamicState.container + \" exited after 120 seconds\");\n+        }\n+        dynamicState.container.forceKill();\n+        Time.sleep(staticState.killSleepMs);\n+        return dynamicState;\n+    }\n+\n+    /**\n+     * State Transitions for WAITING_FOR_WORKER_START state.\n+     * PRECONDITION: container != null && currentAssignment != null\n+     * @param dynamicState current state\n+     * @param staticState static data\n+     * @return the next state\n+     * @throws Exception on any error\n+     */\n+    static DynamicState handleWaitingForWorkerStart(DynamicState dynamicState, StaticState staticState) throws Exception {\n+        assert(dynamicState.container != null);\n+        assert(dynamicState.currentAssignment != null);\n+        \n+        LSWorkerHeartbeat hb = dynamicState.container.readHeartbeat();\n+        if (hb != null) {\n+            long hbAgeMs = (Time.currentTimeSecs() - hb.get_time_secs()) * 1000;\n+            if (hbAgeMs <= staticState.hbTimeoutMs) {\n+                return dynamicState.withState(MachineState.RUNNING);\n+            }\n+        }\n+        \n+        if (!equivalent(dynamicState.newAssignment, dynamicState.currentAssignment)) {\n+            //We were rescheduled while waiting for the worker to come up\n+            return Slot.killContainerForChangedAssignment(dynamicState, staticState);","path":"storm-core/src/jvm/org/apache/storm/daemon/supervisor/Slot.java","position":498,"original_position":498,"commit_id":"e30e08d4644a65025949117b4b73ea49956b6d67","original_commit_id":"e30e08d4644a65025949117b4b73ea49956b6d67","user":{"login":"abellina","id":1901059,"avatar_url":"https://avatars.githubusercontent.com/u/1901059?v=3","gravatar_id":"","url":"https://api.github.com/users/abellina","html_url":"https://github.com/abellina","followers_url":"https://api.github.com/users/abellina/followers","following_url":"https://api.github.com/users/abellina/following{/other_user}","gists_url":"https://api.github.com/users/abellina/gists{/gist_id}","starred_url":"https://api.github.com/users/abellina/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/abellina/subscriptions","organizations_url":"https://api.github.com/users/abellina/orgs","repos_url":"https://api.github.com/users/abellina/repos","events_url":"https://api.github.com/users/abellina/events{/privacy}","received_events_url":"https://api.github.com/users/abellina/received_events","type":"User","site_admin":false},"body":"Add log line to make it consistent with other calls to killContainerForChangedAssignment. Also no need for Slot.\r\n\r\nLOG.warn(\"SLOT {}: Assignment Changed from {} to {}\", staticState.port, dynamicState.currentAs    signment, dynamicState.newAssignment);","created_at":"2016-09-04T19:55:54Z","updated_at":"2016-09-04T19:55:54Z","html_url":"https://github.com/apache/storm/pull/1642#discussion_r77457645","pull_request_url":"https://api.github.com/repos/apache/storm/pulls/1642","_links":{"self":{"href":"https://api.github.com/repos/apache/storm/pulls/comments/77457645"},"html":{"href":"https://github.com/apache/storm/pull/1642#discussion_r77457645"},"pull_request":{"href":"https://api.github.com/repos/apache/storm/pulls/1642"}}},"pull_request":{"url":"https://api.github.com/repos/apache/storm/pulls/1642","id":82254859,"html_url":"https://github.com/apache/storm/pull/1642","diff_url":"https://github.com/apache/storm/pull/1642.diff","patch_url":"https://github.com/apache/storm/pull/1642.patch","issue_url":"https://api.github.com/repos/apache/storm/issues/1642","number":1642,"state":"open","locked":false,"title":"STORM-2018: Supervisor V2.  ","user":{"login":"revans2","id":3441321,"avatar_url":"https://avatars.githubusercontent.com/u/3441321?v=3","gravatar_id":"","url":"https://api.github.com/users/revans2","html_url":"https://github.com/revans2","followers_url":"https://api.github.com/users/revans2/followers","following_url":"https://api.github.com/users/revans2/following{/other_user}","gists_url":"https://api.github.com/users/revans2/gists{/gist_id}","starred_url":"https://api.github.com/users/revans2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/revans2/subscriptions","organizations_url":"https://api.github.com/users/revans2/orgs","repos_url":"https://api.github.com/users/revans2/repos","events_url":"https://api.github.com/users/revans2/events{/privacy}","received_events_url":"https://api.github.com/users/revans2/received_events","type":"User","site_admin":false},"body":"Still needs run as user and CGroup work, but the rest is working\r\n\r\nAny feedback on this would be welcome.  I am particularly interested in the readability of the code and how easy is it to understand vs the original supervisor.\r\n\r\nAll the unit tests pass and I have done a lot of manual testing switching back and forth between the original supervisor and supervisor V2 to ensure that this can be a rolling upgrade.\r\n\r\nThere are still a number of TODOs in the code.  Most of them are for removing the original supervisor code and cleaning up the result of that.","created_at":"2016-08-22T20:12:47Z","updated_at":"2016-09-04T19:55:54Z","closed_at":null,"merged_at":null,"merge_commit_sha":"deae47a676c435abfcd730fa185024cad55f55e0","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/apache/storm/pulls/1642/commits","review_comments_url":"https://api.github.com/repos/apache/storm/pulls/1642/comments","review_comment_url":"https://api.github.com/repos/apache/storm/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/storm/issues/1642/comments","statuses_url":"https://api.github.com/repos/apache/storm/statuses/e30e08d4644a65025949117b4b73ea49956b6d67","head":{"label":"revans2:STORM-2018","ref":"STORM-2018","sha":"e30e08d4644a65025949117b4b73ea49956b6d67","user":{"login":"revans2","id":3441321,"avatar_url":"https://avatars.githubusercontent.com/u/3441321?v=3","gravatar_id":"","url":"https://api.github.com/users/revans2","html_url":"https://github.com/revans2","followers_url":"https://api.github.com/users/revans2/followers","following_url":"https://api.github.com/users/revans2/following{/other_user}","gists_url":"https://api.github.com/users/revans2/gists{/gist_id}","starred_url":"https://api.github.com/users/revans2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/revans2/subscriptions","organizations_url":"https://api.github.com/users/revans2/orgs","repos_url":"https://api.github.com/users/revans2/repos","events_url":"https://api.github.com/users/revans2/events{/privacy}","received_events_url":"https://api.github.com/users/revans2/received_events","type":"User","site_admin":false},"repo":{"id":15404370,"name":"incubator-storm","full_name":"revans2/incubator-storm","owner":{"login":"revans2","id":3441321,"avatar_url":"https://avatars.githubusercontent.com/u/3441321?v=3","gravatar_id":"","url":"https://api.github.com/users/revans2","html_url":"https://github.com/revans2","followers_url":"https://api.github.com/users/revans2/followers","following_url":"https://api.github.com/users/revans2/following{/other_user}","gists_url":"https://api.github.com/users/revans2/gists{/gist_id}","starred_url":"https://api.github.com/users/revans2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/revans2/subscriptions","organizations_url":"https://api.github.com/users/revans2/orgs","repos_url":"https://api.github.com/users/revans2/repos","events_url":"https://api.github.com/users/revans2/events{/privacy}","received_events_url":"https://api.github.com/users/revans2/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/revans2/incubator-storm","description":"Mirror of Apache Storm","fork":true,"url":"https://api.github.com/repos/revans2/incubator-storm","forks_url":"https://api.github.com/repos/revans2/incubator-storm/forks","keys_url":"https://api.github.com/repos/revans2/incubator-storm/keys{/key_id}","collaborators_url":"https://api.github.com/repos/revans2/incubator-storm/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/revans2/incubator-storm/teams","hooks_url":"https://api.github.com/repos/revans2/incubator-storm/hooks","issue_events_url":"https://api.github.com/repos/revans2/incubator-storm/issues/events{/number}","events_url":"https://api.github.com/repos/revans2/incubator-storm/events","assignees_url":"https://api.github.com/repos/revans2/incubator-storm/assignees{/user}","branches_url":"https://api.github.com/repos/revans2/incubator-storm/branches{/branch}","tags_url":"https://api.github.com/repos/revans2/incubator-storm/tags","blobs_url":"https://api.github.com/repos/revans2/incubator-storm/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/revans2/incubator-storm/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/revans2/incubator-storm/git/refs{/sha}","trees_url":"https://api.github.com/repos/revans2/incubator-storm/git/trees{/sha}","statuses_url":"https://api.github.com/repos/revans2/incubator-storm/statuses/{sha}","languages_url":"https://api.github.com/repos/revans2/incubator-storm/languages","stargazers_url":"https://api.github.com/repos/revans2/incubator-storm/stargazers","contributors_url":"https://api.github.com/repos/revans2/incubator-storm/contributors","subscribers_url":"https://api.github.com/repos/revans2/incubator-storm/subscribers","subscription_url":"https://api.github.com/repos/revans2/incubator-storm/subscription","commits_url":"https://api.github.com/repos/revans2/incubator-storm/commits{/sha}","git_commits_url":"https://api.github.com/repos/revans2/incubator-storm/git/commits{/sha}","comments_url":"https://api.github.com/repos/revans2/incubator-storm/comments{/number}","issue_comment_url":"https://api.github.com/repos/revans2/incubator-storm/issues/comments{/number}","contents_url":"https://api.github.com/repos/revans2/incubator-storm/contents/{+path}","compare_url":"https://api.github.com/repos/revans2/incubator-storm/compare/{base}...{head}","merges_url":"https://api.github.com/repos/revans2/incubator-storm/merges","archive_url":"https://api.github.com/repos/revans2/incubator-storm/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/revans2/incubator-storm/downloads","issues_url":"https://api.github.com/repos/revans2/incubator-storm/issues{/number}","pulls_url":"https://api.github.com/repos/revans2/incubator-storm/pulls{/number}","milestones_url":"https://api.github.com/repos/revans2/incubator-storm/milestones{/number}","notifications_url":"https://api.github.com/repos/revans2/incubator-storm/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/revans2/incubator-storm/labels{/name}","releases_url":"https://api.github.com/repos/revans2/incubator-storm/releases{/id}","deployments_url":"https://api.github.com/repos/revans2/incubator-storm/deployments","created_at":"2013-12-23T20:52:06Z","updated_at":"2014-09-18T08:13:24Z","pushed_at":"2016-09-03T20:17:38Z","git_url":"git://github.com/revans2/incubator-storm.git","ssh_url":"git@github.com:revans2/incubator-storm.git","clone_url":"https://github.com/revans2/incubator-storm.git","svn_url":"https://github.com/revans2/incubator-storm","homepage":null,"size":161373,"stargazers_count":1,"watchers_count":1,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":1,"forks":2,"open_issues":1,"watchers":1,"default_branch":"master"}},"base":{"label":"apache:master","ref":"master","sha":"7e15fbe3428664d34e2d2b76a30878315bb3ccaa","user":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":14135470,"name":"storm","full_name":"apache/storm","owner":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/storm","description":"Mirror of Apache Storm","fork":false,"url":"https://api.github.com/repos/apache/storm","forks_url":"https://api.github.com/repos/apache/storm/forks","keys_url":"https://api.github.com/repos/apache/storm/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/storm/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/storm/teams","hooks_url":"https://api.github.com/repos/apache/storm/hooks","issue_events_url":"https://api.github.com/repos/apache/storm/issues/events{/number}","events_url":"https://api.github.com/repos/apache/storm/events","assignees_url":"https://api.github.com/repos/apache/storm/assignees{/user}","branches_url":"https://api.github.com/repos/apache/storm/branches{/branch}","tags_url":"https://api.github.com/repos/apache/storm/tags","blobs_url":"https://api.github.com/repos/apache/storm/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/storm/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/storm/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/storm/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/storm/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/storm/languages","stargazers_url":"https://api.github.com/repos/apache/storm/stargazers","contributors_url":"https://api.github.com/repos/apache/storm/contributors","subscribers_url":"https://api.github.com/repos/apache/storm/subscribers","subscription_url":"https://api.github.com/repos/apache/storm/subscription","commits_url":"https://api.github.com/repos/apache/storm/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/storm/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/storm/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/storm/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/storm/contents/{+path}","compare_url":"https://api.github.com/repos/apache/storm/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/storm/merges","archive_url":"https://api.github.com/repos/apache/storm/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/storm/downloads","issues_url":"https://api.github.com/repos/apache/storm/issues{/number}","pulls_url":"https://api.github.com/repos/apache/storm/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/storm/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/storm/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/storm/labels{/name}","releases_url":"https://api.github.com/repos/apache/storm/releases{/id}","deployments_url":"https://api.github.com/repos/apache/storm/deployments","created_at":"2013-11-05T08:00:14Z","updated_at":"2016-09-04T18:35:05Z","pushed_at":"2016-09-04T14:16:50Z","git_url":"git://github.com/apache/storm.git","ssh_url":"git@github.com:apache/storm.git","clone_url":"https://github.com/apache/storm.git","svn_url":"https://github.com/apache/storm","homepage":null,"size":173967,"stargazers_count":3504,"watchers_count":3504,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":2594,"mirror_url":"git://git.apache.org/storm.git","open_issues_count":137,"forks":2594,"open_issues":137,"watchers":3504,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/storm/pulls/1642"},"html":{"href":"https://github.com/apache/storm/pull/1642"},"issue":{"href":"https://api.github.com/repos/apache/storm/issues/1642"},"comments":{"href":"https://api.github.com/repos/apache/storm/issues/1642/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/storm/pulls/1642/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/storm/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/storm/pulls/1642/commits"},"statuses":{"href":"https://api.github.com/repos/apache/storm/statuses/e30e08d4644a65025949117b4b73ea49956b6d67"}}}}
{"actor":{"display_login":"abellina"}}