Skip to content

Commit f4037ea

Browse files
committed
HADOOP-7122. Fix thread leak when shell commands time out. Contributed by Todd Lipcon
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1064403 13f79535-47bb-0310-9956-ffa450edef68
1 parent 3d35d91 commit f4037ea

File tree

3 files changed

+48
-2
lines changed

3 files changed

+48
-2
lines changed

CHANGES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,8 @@ Release 0.22.0 - Unreleased
457457

458458
HADOOP-7118. Fix NPE in Configuration.writeXml (todd)
459459

460+
HADOOP-7122. Fix thread leak when shell commands time out. (todd)
461+
460462
Release 0.21.1 - Unreleased
461463

462464
IMPROVEMENTS

src/java/org/apache/hadoop/util/Shell.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ private void runCommand() throws IOException {
205205

206206
process = builder.start();
207207
if (timeOutInterval > 0) {
208-
timeOutTimer = new Timer();
208+
timeOutTimer = new Timer("Shell command timeout");
209209
timeoutTimerTask = new ShellTimeoutTimerTask(
210210
this);
211211
//One time scheduling.
@@ -263,7 +263,7 @@ public void run() {
263263
} catch (InterruptedException ie) {
264264
throw new IOException(ie.toString());
265265
} finally {
266-
if ((timeOutTimer!=null) && !timedOut.get()) {
266+
if (timeOutTimer != null) {
267267
timeOutTimer.cancel();
268268
}
269269
// close the input stream

src/test/core/org/apache/hadoop/util/TestShell.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
import java.io.FileOutputStream;
2525
import java.io.IOException;
2626
import java.io.PrintWriter;
27+
import java.lang.management.ManagementFactory;
28+
import java.lang.management.ThreadInfo;
29+
import java.lang.management.ThreadMXBean;
30+
import java.util.Timer;
2731

2832
public class TestShell extends TestCase {
2933

@@ -95,6 +99,46 @@ public void testShellCommandTimeout() throws Throwable {
9599
shellFile.delete();
96100
assertTrue("Script didnt not timeout" , shexc.isTimedOut());
97101
}
102+
103+
private static int countTimerThreads() {
104+
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
105+
106+
int count = 0;
107+
ThreadInfo[] infos = threadBean.getThreadInfo(threadBean.getAllThreadIds(), 20);
108+
for (ThreadInfo info : infos) {
109+
if (info == null) continue;
110+
for (StackTraceElement elem : info.getStackTrace()) {
111+
if (elem.getClassName().contains("Timer")) {
112+
count++;
113+
break;
114+
}
115+
}
116+
}
117+
return count;
118+
}
119+
120+
public void testShellCommandTimerLeak() throws Exception {
121+
String quickCommand[] = new String[] {"/bin/sleep", "100"};
122+
123+
int timersBefore = countTimerThreads();
124+
System.err.println("before: " + timersBefore);
125+
126+
for (int i = 0; i < 10; i++) {
127+
Shell.ShellCommandExecutor shexec = new Shell.ShellCommandExecutor(
128+
quickCommand, null, null, 1);
129+
try {
130+
shexec.execute();
131+
fail("Bad command should throw exception");
132+
} catch (Exception e) {
133+
// expected
134+
}
135+
}
136+
Thread.sleep(1000);
137+
int timersAfter = countTimerThreads();
138+
System.err.println("after: " + timersAfter);
139+
assertEquals(timersBefore, timersAfter);
140+
}
141+
98142

99143
private void testInterval(long interval) throws IOException {
100144
Command command = new Command(interval);

0 commit comments

Comments
 (0)