diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-01-08 15:51:06 +0100 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-01-13 13:42:43 +0100 |
commit | 255e54d582d02ab72d1b33f440656fb2d5ae9f8c (patch) | |
tree | 57c23abb47875009240b3e442801b58d8c3237ab /server | |
parent | 1d49769ae87ac8a2a553815bf2bfc9bf17a85f8f (diff) | |
download | sonarqube-255e54d582d02ab72d1b33f440656fb2d5ae9f8c.tar.gz sonarqube-255e54d582d02ab72d1b33f440656fb2d5ae9f8c.zip |
SONAR-7168 fix stop failing during restart + restart WS call flood issue
stop triggered though shareMemory by Orchestrator did not work when a restart was under way be lifeCycle transition from RESTARTING to STOPPING wasn't allowed
when flooding the restart WS, the restart never occured because the WS erased the shareMemory space of the WebServer when called called, erasing the stop signal sent by the main process
Diffstat (limited to 'server')
5 files changed, 53 insertions, 38 deletions
diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java index 98498c0e17e..749389d1054 100644 --- a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java +++ b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java @@ -188,15 +188,16 @@ public class Monitor { private void cleanAfterTermination() { trace("go to STOPPED..."); // safeguard if TerminatorThread is buggy and stop restartWatcher - lifecycle.tryToMoveTo(State.STOPPED); - trace("await termination of restartWatcher..."); - // wait for restartWatcher to cleanly stop - awaitTermination(restartWatcher); - trace("restartWatcher done"); - // removing shutdown hook to avoid called stop() unnecessarily unless already in shutdownHook - if (!systemExit.isInShutdownHook()) { - trace("removing shutdown hook..."); - Runtime.getRuntime().removeShutdownHook(shutdownHook); + if (lifecycle.tryToMoveTo(State.STOPPED)) { + trace("await termination of restartWatcher..."); + // wait for restartWatcher to cleanly stop + awaitTermination(restartWatcher); + trace("restartWatcher done"); + // removing shutdown hook to avoid called stop() unnecessarily unless already in shutdownHook + if (!systemExit.isInShutdownHook()) { + trace("removing shutdown hook..."); + Runtime.getRuntime().removeShutdownHook(shutdownHook); + } } } @@ -288,7 +289,7 @@ public class Monitor { } private void stopProcesses() { - ArrayList<WatcherThread> watcherThreads = new ArrayList<>(this.watcherThreads); + List<WatcherThread> watcherThreads = new ArrayList<>(this.watcherThreads); // create a copy and reverse it to terminate in reverse order of startup (dependency order) Collections.reverse(watcherThreads); diff --git a/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java b/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java index 3ceab37472e..b00a9bb91fa 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java +++ b/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java @@ -75,6 +75,10 @@ public class DefaultProcessCommands implements ProcessCommands { private int processNumber; public DefaultProcessCommands(File directory, int processNumber) { + this(directory, processNumber, true); + } + + public DefaultProcessCommands(File directory, int processNumber, boolean clean) { // processNumber should not excess MAX_PROCESSES and must not be below -1 assert processNumber <= MAX_PROCESSES : "Incorrect process number"; assert processNumber >= -1 : "Incorrect process number"; @@ -87,7 +91,9 @@ public class DefaultProcessCommands implements ProcessCommands { try { sharedMemory = new RandomAccessFile(new File(directory, "sharedmemory"), "rw"); mappedByteBuffer = sharedMemory.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, MAX_SHARED_MEMORY); - cleanData(); + if (clean) { + cleanData(); + } } catch (IOException e) { throw new IllegalArgumentException("Unable to create shared memory : ", e); } diff --git a/server/sonar-process/src/main/java/org/sonar/process/Lifecycle.java b/server/sonar-process/src/main/java/org/sonar/process/Lifecycle.java index 18c74daabac..6aa8e1d932b 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/Lifecycle.java +++ b/server/sonar-process/src/main/java/org/sonar/process/Lifecycle.java @@ -20,7 +20,7 @@ package org.sonar.process; import java.util.Collections; -import java.util.HashMap; +import java.util.EnumMap; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -28,6 +28,13 @@ import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.sonar.process.Lifecycle.State.INIT; +import static org.sonar.process.Lifecycle.State.RESTARTING; +import static org.sonar.process.Lifecycle.State.STARTED; +import static org.sonar.process.Lifecycle.State.STARTING; +import static org.sonar.process.Lifecycle.State.STOPPED; +import static org.sonar.process.Lifecycle.State.STOPPING; + public class Lifecycle { private static final Logger LOG = LoggerFactory.getLogger(Lifecycle.class); @@ -38,13 +45,13 @@ public class Lifecycle { private static final Map<State, Set<State>> TRANSITIONS = buildTransitions(); private static Map<State, Set<State>> buildTransitions() { - Map<State, Set<State>> res = new HashMap<>(State.values().length); - res.put(State.INIT, toSet(State.STARTING)); - res.put(State.STARTING, toSet(State.STARTED, State.STOPPING)); - res.put(State.STARTED, toSet(State.RESTARTING, State.STOPPING)); - res.put(State.RESTARTING, toSet(State.STARTING)); - res.put(State.STOPPING, toSet(State.STOPPED)); - res.put(State.STOPPED, toSet()); + Map<State, Set<State>> res = new EnumMap<>(State.class); + res.put(INIT, toSet(STARTING)); + res.put(STARTING, toSet(STARTED, STOPPING)); + res.put(STARTED, toSet(RESTARTING, STOPPING)); + res.put(RESTARTING, toSet(STARTING, STOPPING)); + res.put(STOPPING, toSet(STOPPED)); + res.put(STOPPED, toSet()); return res; } @@ -60,7 +67,7 @@ public class Lifecycle { return res; } - private State state = State.INIT; + private State state = INIT; public State getState() { return state; @@ -73,7 +80,7 @@ public class Lifecycle { this.state = to; res = true; } - LOG.trace("tryToMoveTo from {} to {} => {}", currentState, to, res); + LOG.info("tryToMoveTo from {} to {} => {}", currentState, to, res); return res; } diff --git a/server/sonar-process/src/test/java/org/sonar/process/LifecycleTest.java b/server/sonar-process/src/test/java/org/sonar/process/LifecycleTest.java index fa9d925d159..6337fe60e74 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/LifecycleTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/LifecycleTest.java @@ -23,6 +23,7 @@ import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.process.Lifecycle.State; +import static org.sonar.process.Lifecycle.State.*; public class LifecycleTest { @@ -37,34 +38,34 @@ public class LifecycleTest { // different state Lifecycle stopping = new Lifecycle(); - stopping.tryToMoveTo(State.STARTING); + stopping.tryToMoveTo(STARTING); assertThat(stopping).isNotEqualTo(init); } @Test public void try_to_move_does_not_support_jumping_states() { Lifecycle lifecycle = new Lifecycle(); - assertThat(lifecycle.getState()).isEqualTo(State.INIT); + assertThat(lifecycle.getState()).isEqualTo(INIT); - assertThat(lifecycle.tryToMoveTo(State.STARTED)).isFalse(); - assertThat(lifecycle.getState()).isEqualTo(State.INIT); + assertThat(lifecycle.tryToMoveTo(STARTED)).isFalse(); + assertThat(lifecycle.getState()).isEqualTo(INIT); - assertThat(lifecycle.tryToMoveTo(State.STARTING)).isTrue(); - assertThat(lifecycle.getState()).isEqualTo(State.STARTING); + assertThat(lifecycle.tryToMoveTo(STARTING)).isTrue(); + assertThat(lifecycle.getState()).isEqualTo(STARTING); } @Test public void no_state_can_not_move_to_itself() { - for (State state : State.values()) { + for (State state : values()) { assertThat(newLifeCycle(state).tryToMoveTo(state)).isFalse(); } } @Test public void can_move_to_STOPPING_from_any_state_but_STARTING_and_STARTED_only() { - for (State state : State.values()) { - boolean tryToMoveTo = newLifeCycle(state).tryToMoveTo(State.STOPPING); - if (state == State.STARTING || state == State.STARTED) { + for (State state : values()) { + boolean tryToMoveTo = newLifeCycle(state).tryToMoveTo(STOPPING); + if (state == STARTING || state == STARTED || state == RESTARTING) { assertThat(tryToMoveTo).describedAs("from state " + state).isTrue(); } else { assertThat(tryToMoveTo).describedAs("from state " + state).isFalse(); @@ -74,7 +75,7 @@ public class LifecycleTest { @Test public void can_move_to_STARTING_from_RESTARTING() { - assertThat(newLifeCycle(State.RESTARTING).tryToMoveTo(State.STARTING)).isTrue(); + assertThat(newLifeCycle(RESTARTING).tryToMoveTo(STARTING)).isTrue(); } private static Lifecycle newLifeCycle(State state) { @@ -82,15 +83,15 @@ public class LifecycleTest { case INIT: return new Lifecycle(); case STARTING: - return newLifeCycle(State.INIT, state); + return newLifeCycle(INIT, state); case STARTED: - return newLifeCycle(State.STARTING, state); + return newLifeCycle(STARTING, state); case RESTARTING: - return newLifeCycle(State.STARTED, state); + return newLifeCycle(STARTED, state); case STOPPING: - return newLifeCycle(State.STARTED, state); + return newLifeCycle(STARTED, state); case STOPPED: - return newLifeCycle(State.STOPPING, state); + return newLifeCycle(STOPPING, state); default: throw new IllegalArgumentException("Unsupported state " + state); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/RestartAction.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/RestartAction.java index d2caac6a8eb..0d395e89199 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/RestartAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/RestartAction.java @@ -75,7 +75,7 @@ public class RestartAction implements SystemWsAction { LOGGER.info("Requesting SonarQube restart"); userSession.checkPermission(UserRole.ADMIN); ProcessCommands commands = new DefaultProcessCommands( - nonNullValueAsFile(PROPERTY_SHARED_PATH), nonNullAsInt(PROPERTY_PROCESS_INDEX)); + nonNullValueAsFile(PROPERTY_SHARED_PATH), nonNullAsInt(PROPERTY_PROCESS_INDEX), false); commands.askForRestart(); } response.noContent(); |