From 99d84905d981395e5026f693f7a948f31a40007a Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Wed, 9 Mar 2016 12:01:36 +0100 Subject: [PATCH] SONAR-7435 add operational flag to shared memory IPC --- .../sonar/process/AllProcessesCommands.java | 28 +++++- .../sonar/process/DefaultProcessCommands.java | 10 +++ .../org/sonar/process/ProcessCommands.java | 9 ++ .../process/AllProcessesCommandsTest.java | 85 ++++++++++++------- 4 files changed, 100 insertions(+), 32 deletions(-) diff --git a/server/sonar-process/src/main/java/org/sonar/process/AllProcessesCommands.java b/server/sonar-process/src/main/java/org/sonar/process/AllProcessesCommands.java index 52f5bcfd9fd..fe11a0e9fa3 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/AllProcessesCommands.java +++ b/server/sonar-process/src/main/java/org/sonar/process/AllProcessesCommands.java @@ -53,6 +53,7 @@ import static org.sonar.process.ProcessCommands.MAX_PROCESSES; *
  • First byte contains {@link #EMPTY} until process is UP and writes {@link #UP}
  • *
  • Second byte contains {@link #EMPTY} until any process requests current one to stop by writing value {@link #STOP}
  • *
  • Third byte contains {@link #EMPTY} until any process requests current one to restart by writing value {@link #RESTART}. Process acknowledges restart by writing back {@link #EMPTY}
  • + *
  • Fourth byte will always contain {@link #EMPTY} unless process declares that it is operational by writing {@link #OPERATIONAL}. This does not imply that is done starting.
  • *
  • The next 8 bytes contains a long (value of {@link System#currentTimeMillis()}) which represents the date of the last ping
  • * *

    @@ -61,15 +62,17 @@ public class AllProcessesCommands { private static final int UP_BYTE_OFFSET = 0; private static final int STOP_BYTE_OFFSET = 1; private static final int RESTART_BYTE_OFFSET = 2; - private static final int PING_BYTE_OFFSET = 3; + private static final int OPERATIONAL_BYTE_OFFSET = 3; + private static final int PING_BYTE_OFFSET = 4; - private static final int BYTE_LENGTH_FOR_ONE_PROCESS = 1 + 1 + 1 + 8; + private static final int BYTE_LENGTH_FOR_ONE_PROCESS = 1 + 1 + 1 + 1 + 8; // With this shared memory we can handle up to MAX_PROCESSES processes private static final int MAX_SHARED_MEMORY = BYTE_LENGTH_FOR_ONE_PROCESS * MAX_PROCESSES; private static final byte STOP = (byte) 0xFF; private static final byte RESTART = (byte) 0xAA; + private static final byte OPERATIONAL = (byte) 0x59; private static final byte UP = (byte) 0x01; private static final byte EMPTY = (byte) 0x00; @@ -118,6 +121,17 @@ public class AllProcessesCommands { writeByte(processNumber, UP_BYTE_OFFSET, UP); } + boolean isOperational(int processNumber) { + return readByte(processNumber, OPERATIONAL_BYTE_OFFSET) == OPERATIONAL; + } + + /** + * To be executed by child process to declare that it is started and fully operational + */ + void setOperational(int processNumber) { + writeByte(processNumber, OPERATIONAL_BYTE_OFFSET, OPERATIONAL); + } + void ping(int processNumber) { writeLong(processNumber, PING_BYTE_OFFSET, System.currentTimeMillis()); } @@ -205,6 +219,16 @@ public class AllProcessesCommands { AllProcessesCommands.this.setUp(processNumber); } + @Override + public boolean isOperational() { + return AllProcessesCommands.this.isOperational(processNumber); + } + + @Override + public void setOperational() { + AllProcessesCommands.this.setOperational(processNumber); + } + @Override public void ping() { AllProcessesCommands.this.ping(processNumber); 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 0ef4413aa75..6d726ee9172 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 @@ -49,6 +49,16 @@ public class DefaultProcessCommands implements ProcessCommands { delegate.setUp(); } + @Override + public boolean isOperational() { + return delegate.isOperational(); + } + + @Override + public void setOperational() { + delegate.setOperational(); + } + @Override public void ping() { delegate.ping(); diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java index f52f5b5f5df..1057ad54158 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java +++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java @@ -41,6 +41,15 @@ public interface ProcessCommands extends AutoCloseable { */ void setUp(); + boolean isOperational(); + + /** + * To be executed by child process to declare that it is done starting and fully operational. + * + * @throws IllegalStateException if {@link #setUp()} has not been called + */ + void setOperational(); + void ping(); long getLastPing(); diff --git a/server/sonar-process/src/test/java/org/sonar/process/AllProcessesCommandsTest.java b/server/sonar-process/src/test/java/org/sonar/process/AllProcessesCommandsTest.java index ad92121b824..bda42cf07e7 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/AllProcessesCommandsTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/AllProcessesCommandsTest.java @@ -20,6 +20,7 @@ package org.sonar.process; import java.io.File; +import java.io.IOException; import org.apache.commons.io.FileUtils; import org.junit.Rule; import org.junit.Test; @@ -36,6 +37,7 @@ public class AllProcessesCommandsTest { private static final byte STOP = (byte) 0xFF; private static final byte RESTART = (byte) 0xAA; private static final byte UP = (byte) 0x01; + private static final byte OPERATIONAL = (byte) 0x59; private static final byte EMPTY = (byte) 0x00; @Rule @@ -57,84 +59,101 @@ public class AllProcessesCommandsTest { } @Test - public void child_process_update_the_mapped_memory() throws Exception { - File dir = temp.newFolder(); + public void write_and_read_up() throws IOException { + AllProcessesCommands commands = new AllProcessesCommands(temp.newFolder()); + int offset = 0; - AllProcessesCommands commands = new AllProcessesCommands(dir); assertThat(commands.isUp(PROCESS_NUMBER)).isFalse(); - assertThat(commands.mappedByteBuffer.get(commands.offset(PROCESS_NUMBER))).isEqualTo(EMPTY); - assertThat(commands.mappedByteBuffer.getLong(2 + commands.offset(PROCESS_NUMBER))).isEqualTo(0L); + assertThat(readByte(commands, offset)).isEqualTo(EMPTY); commands.setUp(PROCESS_NUMBER); assertThat(commands.isUp(PROCESS_NUMBER)).isTrue(); - assertThat(commands.mappedByteBuffer.get(commands.offset(PROCESS_NUMBER))).isEqualTo(UP); + assertThat(readByte(commands, offset)).isEqualTo(UP); + } + + @Test + public void write_and_read_operational() throws IOException { + AllProcessesCommands commands = new AllProcessesCommands(temp.newFolder()); + int offset = 3; + + assertThat(commands.isOperational(PROCESS_NUMBER)).isFalse(); + assertThat(readByte(commands, offset)).isEqualTo(EMPTY); + + commands.setOperational(PROCESS_NUMBER); + assertThat(commands.isOperational(PROCESS_NUMBER)).isTrue(); + assertThat(readByte(commands, offset)).isEqualTo(OPERATIONAL); + } + + @Test + public void write_and_read_ping() throws IOException { + AllProcessesCommands commands = new AllProcessesCommands(temp.newFolder()); + + int offset = 4; + assertThat(readLong(commands, offset)).isEqualTo(0L); long currentTime = System.currentTimeMillis(); commands.ping(PROCESS_NUMBER); - assertThat(commands.mappedByteBuffer.getLong(3 + commands.offset(PROCESS_NUMBER))).isGreaterThanOrEqualTo(currentTime); + assertThat(readLong(commands, offset)).isGreaterThanOrEqualTo(currentTime); } @Test public void ask_for_stop() throws Exception { - File dir = temp.newFolder(); + AllProcessesCommands commands = new AllProcessesCommands(temp.newFolder()); + int offset = 1; - AllProcessesCommands commands = new AllProcessesCommands(dir); - assertThat(commands.mappedByteBuffer.get(commands.offset(PROCESS_NUMBER) + 1)).isNotEqualTo(STOP); + assertThat(readByte(commands, offset)).isNotEqualTo(STOP); assertThat(commands.askedForStop(PROCESS_NUMBER)).isFalse(); commands.askForStop(PROCESS_NUMBER); assertThat(commands.askedForStop(PROCESS_NUMBER)).isTrue(); - assertThat(commands.mappedByteBuffer.get(commands.offset(PROCESS_NUMBER) + 1)).isEqualTo(STOP); + assertThat(readByte(commands, offset)).isEqualTo(STOP); } @Test public void ask_for_restart() throws Exception { - File dir = temp.newFolder(); + AllProcessesCommands commands = new AllProcessesCommands(temp.newFolder()); + int offset = 2; - AllProcessesCommands commands = new AllProcessesCommands(dir); - assertThat(commands.mappedByteBuffer.get(commands.offset(PROCESS_NUMBER) +2)).isNotEqualTo(RESTART); + assertThat(readByte(commands, offset)).isNotEqualTo(RESTART); assertThat(commands.askedForRestart(PROCESS_NUMBER)).isFalse(); commands.askForRestart(PROCESS_NUMBER); assertThat(commands.askedForRestart(PROCESS_NUMBER)).isTrue(); - assertThat(commands.mappedByteBuffer.get(commands.offset(PROCESS_NUMBER) + 2)).isEqualTo(RESTART); + assertThat(readByte(commands, offset)).isEqualTo(RESTART); } @Test public void acknowledgeAskForRestart_has_no_effect_when_no_restart_asked() throws Exception { - File dir = temp.newFolder(); + AllProcessesCommands commands = new AllProcessesCommands(temp.newFolder()); + int offset = 2; - AllProcessesCommands commands = new AllProcessesCommands(dir); - assertThat(commands.mappedByteBuffer.get(commands.offset(PROCESS_NUMBER) + 2)).isNotEqualTo(RESTART); + assertThat(readByte(commands, offset)).isNotEqualTo(RESTART); assertThat(commands.askedForRestart(PROCESS_NUMBER)).isFalse(); commands.acknowledgeAskForRestart(PROCESS_NUMBER); - assertThat(commands.mappedByteBuffer.get(commands.offset(PROCESS_NUMBER) + 2)).isNotEqualTo(RESTART); + assertThat(readByte(commands, offset)).isNotEqualTo(RESTART); assertThat(commands.askedForRestart(PROCESS_NUMBER)).isFalse(); } @Test public void acknowledgeAskForRestart_resets_askForRestart_has_no_effect_when_no_restart_asked() throws Exception { - File dir = temp.newFolder(); - - AllProcessesCommands commands = new AllProcessesCommands(dir); + AllProcessesCommands commands = new AllProcessesCommands(temp.newFolder()); + int offset = 2; commands.askForRestart(PROCESS_NUMBER); assertThat(commands.askedForRestart(PROCESS_NUMBER)).isTrue(); - assertThat(commands.mappedByteBuffer.get(commands.offset(PROCESS_NUMBER) + 2)).isEqualTo(RESTART); + assertThat(readByte(commands, offset)).isEqualTo(RESTART); commands.acknowledgeAskForRestart(PROCESS_NUMBER); - assertThat(commands.mappedByteBuffer.get(commands.offset(PROCESS_NUMBER) + 2)).isNotEqualTo(RESTART); + assertThat(readByte(commands, offset)).isNotEqualTo(RESTART); assertThat(commands.askedForRestart(PROCESS_NUMBER)).isFalse(); } @Test public void getProcessCommands_fails_if_processNumber_is_less_than_0() throws Exception { - File dir = temp.newFolder(); + AllProcessesCommands allProcessesCommands = new AllProcessesCommands(temp.newFolder()); int processNumber = -2; - AllProcessesCommands allProcessesCommands = new AllProcessesCommands(dir); - expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Process number " + processNumber + " is not valid"); @@ -143,14 +162,20 @@ public class AllProcessesCommandsTest { @Test public void getProcessCommands_fails_if_processNumber_is_higher_than_MAX_PROCESSES() throws Exception { - File dir = temp.newFolder(); + AllProcessesCommands allProcessesCommands = new AllProcessesCommands(temp.newFolder()); int processNumber = MAX_PROCESSES + 1; - AllProcessesCommands allProcessesCommands = new AllProcessesCommands(dir); - expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Process number " + processNumber + " is not valid"); allProcessesCommands.createAfterClean(processNumber); } + + private byte readByte(AllProcessesCommands commands, int offset) { + return commands.mappedByteBuffer.get(commands.offset(PROCESS_NUMBER) + offset); + } + + private long readLong(AllProcessesCommands commands, int offset) { + return commands.mappedByteBuffer.getLong(offset + commands.offset(PROCESS_NUMBER)); + } } -- 2.39.5