Skip to content

Commit 68a0a95

Browse files
committed
guard against corrupt lock files
1 parent 20e27eb commit 68a0a95

2 files changed

Lines changed: 75 additions & 32 deletions

File tree

affinity/src/main/java/net/openhft/affinity/LockCheck.java

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
package net.openhft.affinity;
1919

2020
import org.jetbrains.annotations.NotNull;
21+
import org.slf4j.Logger;
22+
import org.slf4j.LoggerFactory;
2123

2224
import java.io.*;
2325
import java.text.SimpleDateFormat;
@@ -30,20 +32,11 @@
3032
enum LockCheck {
3133
;
3234

33-
static final String TMP = System.getProperty("java.io.tmpdir");
34-
public static final String TARGET = System.getProperty("project.build.directory", findTarget());
35+
private static final Logger LOGGER = LoggerFactory.getLogger(LockCheck.class);
3536
private static final String OS = System.getProperty("os.name").toLowerCase();
36-
static final boolean IS_LINUX = OS.startsWith("linux");
37+
private static final int EMPTY_PID = Integer.MIN_VALUE;
3738
private static SimpleDateFormat df = new SimpleDateFormat("yyyy.MM" + ".dd 'at' HH:mm:ss z");
38-
39-
private static String findTarget() {
40-
for (File dir = new File(System.getProperty("user.dir")); dir != null; dir = dir.getParentFile()) {
41-
File target = new File(dir, "target");
42-
if (target.exists())
43-
return target.getAbsolutePath();
44-
}
45-
return TMP + "/target";
46-
}
39+
static final boolean IS_LINUX = OS.startsWith("linux");
4740

4841
static long getPID() {
4942
String processName =
@@ -65,10 +58,15 @@ public static boolean isCpuFree(int cpu) {
6558
int currentProcess = 0;
6659
try {
6760
currentProcess = getProcessForCpu(file);
68-
} catch (IOException e) {
61+
} catch (RuntimeException | IOException e) {
62+
LOGGER.warn("Failed to determine process on cpu " + cpu, e);
6963
e.printStackTrace();
7064
return true;
7165
}
66+
if (currentProcess == EMPTY_PID) {
67+
file.delete();
68+
return true;
69+
}
7270
if (!isProcessRunning(currentProcess)) {
7371
file.delete();
7472
return true;
@@ -78,7 +76,7 @@ public static boolean isCpuFree(int cpu) {
7876
}
7977

8078
@NotNull
81-
private static File toFile(int core) {
79+
static File toFile(int core) {
8280
return new File(tmpDir(), "cpu-" + core + ".lock");
8381
}
8482

@@ -104,7 +102,7 @@ static boolean isProcessRunning(long pid) {
104102
*/
105103
private synchronized static void storePid(long processID, File coreFile) throws IOException {
106104
try (Writer writer = new BufferedWriter(new OutputStreamWriter(
107-
new FileOutputStream(coreFile), "utf-8"))) {
105+
new FileOutputStream(coreFile, false), "utf-8"))) {
108106
String processIDStr = Long.toString(processID);
109107
writer.write(processIDStr + "\n" + df.format(new Date()));
110108
}
@@ -115,10 +113,22 @@ static int getProcessForCpu(int core) throws IOException {
115113
}
116114

117115
private static int getProcessForCpu(@NotNull File coreFile) throws IOException {
118-
try (LineNumberReader reader = new LineNumberReader(
119-
new BufferedReader(new InputStreamReader(new FileInputStream(coreFile), "utf-8")))) {
120-
String s = reader.readLine().trim();
121-
return Integer.parseInt(s);
116+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
117+
new FileInputStream(coreFile), "utf-8"))) {
118+
119+
final String firstLine = reader.readLine();
120+
if (firstLine == null) {
121+
LOGGER.warn("Empty lock file {}", coreFile.getAbsolutePath());
122+
return EMPTY_PID;
123+
}
124+
String s = firstLine.trim();
125+
try {
126+
return Integer.parseInt(s);
127+
} catch (RuntimeException e) {
128+
LOGGER.warn("Corrupt lock file {}: first line = '{}'", coreFile.getAbsolutePath(), firstLine);
129+
e.printStackTrace();
130+
return EMPTY_PID;
131+
}
122132
}
123133
}
124134

@@ -137,9 +147,8 @@ static void updateCpu(int cpu) {
137147
try {
138148
replacePid(toFile(cpu), getPID());
139149
} catch (IOException e) {
150+
LOGGER.warn("Failed to update lock file for cpu " + cpu, e);
140151
e.printStackTrace();
141152
}
142153
}
143-
144-
145-
}
154+
}

affinity/src/test/java/net/openhft/affinity/LockCheckTest.java

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
import org.junit.Before;
2323
import org.junit.Test;
2424

25+
import java.io.File;
26+
import java.io.FileWriter;
2527
import java.io.IOException;
28+
import java.io.RandomAccessFile;
2629

2730
import static net.openhft.affinity.LockCheck.IS_LINUX;
2831

@@ -31,19 +34,21 @@
3134
*/
3235
public class LockCheckTest {
3336

34-
private static int CPU = 1111;
37+
private static final String TMP = System.getProperty("java.io.tmpdir");
38+
private static final String TARGET = System.getProperty("project.build.directory", findTarget());
39+
private int cpu = 1111;
3540

3641
@Before
3742
public void before() {
3843
Assume.assumeTrue(IS_LINUX);
39-
System.setProperty("java.io.tmpdir", LockCheck.TARGET + "/" + System.nanoTime());
44+
System.setProperty("java.io.tmpdir", TARGET + "/" + System.nanoTime());
4045
}
4146

4247
@Test
4348
public void test() throws IOException {
44-
Assert.assertTrue(LockCheck.isCpuFree(CPU));
45-
LockCheck.updateCpu(CPU);
46-
Assert.assertEquals(LockCheck.getPID(), LockCheck.getProcessForCpu(CPU));
49+
Assert.assertTrue(LockCheck.isCpuFree(cpu));
50+
LockCheck.updateCpu(cpu);
51+
Assert.assertEquals(LockCheck.getPID(), LockCheck.getProcessForCpu(cpu));
4752
}
4853

4954
@Test
@@ -53,11 +58,40 @@ public void testPidOnLinux() {
5358

5459
@Test
5560
public void testReplace() throws IOException {
56-
CPU++;
57-
Assert.assertTrue(LockCheck.isCpuFree(CPU + 1));
58-
LockCheck.replacePid(CPU, 123L);
59-
Assert.assertEquals(123L, LockCheck.getProcessForCpu(CPU));
61+
cpu++;
62+
Assert.assertTrue(LockCheck.isCpuFree(cpu + 1));
63+
LockCheck.replacePid(cpu, 123L);
64+
Assert.assertEquals(123L, LockCheck.getProcessForCpu(cpu));
6065
}
6166

67+
@Test
68+
public void shouldNotBlowUpIfPidFileIsEmpty() throws Exception {
69+
LockCheck.updateCpu(cpu);
70+
71+
final File file = LockCheck.toFile(cpu);
72+
new RandomAccessFile(file, "rw").setLength(0);
73+
74+
LockCheck.isCpuFree(cpu);
75+
}
76+
77+
@Test
78+
public void shouldNotBlowUpIfPidFileIsCorrupt() throws Exception {
79+
LockCheck.updateCpu(cpu);
80+
81+
final File file = LockCheck.toFile(cpu);
82+
try (final FileWriter writer = new FileWriter(file, false)) {
83+
writer.append("not a number\nnot a date");
84+
}
6285

63-
}
86+
LockCheck.isCpuFree(cpu);
87+
}
88+
89+
private static String findTarget() {
90+
for (File dir = new File(System.getProperty("user.dir")); dir != null; dir = dir.getParentFile()) {
91+
File target = new File(dir, "target");
92+
if (target.exists())
93+
return target.getAbsolutePath();
94+
}
95+
return TMP + "/target";
96+
}
97+
}

0 commit comments

Comments
 (0)