|
@@ -24,13 +24,16 @@ import java.io.FileWriter;
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
import java.util.Random;
|
|
import java.util.Random;
|
|
import java.util.Vector;
|
|
import java.util.Vector;
|
|
|
|
+import java.util.regex.Matcher;
|
|
|
|
+import java.util.regex.Pattern;
|
|
|
|
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
import org.apache.commons.logging.LogFactory;
|
|
import org.apache.hadoop.fs.FileUtil;
|
|
import org.apache.hadoop.fs.FileUtil;
|
|
import org.apache.hadoop.fs.Path;
|
|
import org.apache.hadoop.fs.Path;
|
|
-import org.apache.hadoop.mapred.UtilsForTests;
|
|
|
|
|
|
+import org.apache.hadoop.util.StringUtils;
|
|
import org.apache.hadoop.util.Shell.ExitCodeException;
|
|
import org.apache.hadoop.util.Shell.ExitCodeException;
|
|
|
|
+import org.apache.hadoop.mapred.UtilsForTests;
|
|
import org.apache.hadoop.util.Shell.ShellCommandExecutor;
|
|
import org.apache.hadoop.util.Shell.ShellCommandExecutor;
|
|
|
|
|
|
import junit.framework.TestCase;
|
|
import junit.framework.TestCase;
|
|
@@ -160,6 +163,10 @@ public class TestProcfsBasedProcessTree extends TestCase {
|
|
|
|
|
|
p = p.getProcessTree(); // reconstruct
|
|
p = p.getProcessTree(); // reconstruct
|
|
LOG.info("ProcessTree: " + p.toString());
|
|
LOG.info("ProcessTree: " + p.toString());
|
|
|
|
+
|
|
|
|
+ // Get the process-tree dump
|
|
|
|
+ String processTreeDump = p.getProcessTreeDump();
|
|
|
|
+
|
|
// destroy the map task and all its subprocesses
|
|
// destroy the map task and all its subprocesses
|
|
p.destroy(true/*in the background*/);
|
|
p.destroy(true/*in the background*/);
|
|
if(ProcessTree.isSetsidAvailable) {// whole processtree should be gone
|
|
if(ProcessTree.isSetsidAvailable) {// whole processtree should be gone
|
|
@@ -168,6 +175,21 @@ public class TestProcfsBasedProcessTree extends TestCase {
|
|
else {// process should be gone
|
|
else {// process should be gone
|
|
assertEquals(false, p.isAlive());
|
|
assertEquals(false, p.isAlive());
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ LOG.info("Process-tree dump follows: \n" + processTreeDump);
|
|
|
|
+ assertTrue("Process-tree dump doesn't start with a proper header",
|
|
|
|
+ processTreeDump.startsWith("\t|- PID PPID PGRPID SESSID CMD_NAME "
|
|
|
|
+ + "VMEM_USAGE(BYTES) FULL_CMD_LINE\n"));
|
|
|
|
+ for (int i = N; i >= 0; i--) {
|
|
|
|
+ String cmdLineDump =
|
|
|
|
+ "\\|- [0-9]+ [0-9]+ [0-9]+ [0-9]+ \\(sh\\) [0-9]+ sh " + shellScript
|
|
|
|
+ + " " + i;
|
|
|
|
+ Pattern pat = Pattern.compile(cmdLineDump);
|
|
|
|
+ Matcher mat = pat.matcher(processTreeDump);
|
|
|
|
+ assertTrue("Process-tree dump doesn't contain the cmdLineDump of " + i
|
|
|
|
+ + "th process!", mat.find());
|
|
|
|
+ }
|
|
|
|
+
|
|
// Not able to join thread sometimes when forking with large N.
|
|
// Not able to join thread sometimes when forking with large N.
|
|
try {
|
|
try {
|
|
t.join(2000);
|
|
t.join(2000);
|
|
@@ -350,6 +372,88 @@ public class TestProcfsBasedProcessTree extends TestCase {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Test the correctness of process-tree dump.
|
|
|
|
+ *
|
|
|
|
+ * @throws IOException
|
|
|
|
+ */
|
|
|
|
+ public void testProcessTreeDump()
|
|
|
|
+ throws IOException {
|
|
|
|
+
|
|
|
|
+ String[] pids = { "100", "200", "300", "400", "500", "600" };
|
|
|
|
+
|
|
|
|
+ File procfsRootDir = new File(TEST_ROOT_DIR, "proc");
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ setupProcfsRootDir(procfsRootDir);
|
|
|
|
+ setupPidDirs(procfsRootDir, pids);
|
|
|
|
+
|
|
|
|
+ int numProcesses = pids.length;
|
|
|
|
+ // Processes 200, 300, 400 and 500 are descendants of 100. 600 is not.
|
|
|
|
+ ProcessStatInfo[] procInfos = new ProcessStatInfo[numProcesses];
|
|
|
|
+ procInfos[0] =
|
|
|
|
+ new ProcessStatInfo(new String[] { "100", "proc1", "1", "100",
|
|
|
|
+ "100", "100000" });
|
|
|
|
+ procInfos[1] =
|
|
|
|
+ new ProcessStatInfo(new String[] { "200", "proc2", "100", "100",
|
|
|
|
+ "100", "200000" });
|
|
|
|
+ procInfos[2] =
|
|
|
|
+ new ProcessStatInfo(new String[] { "300", "proc3", "200", "100",
|
|
|
|
+ "100", "300000" });
|
|
|
|
+ procInfos[3] =
|
|
|
|
+ new ProcessStatInfo(new String[] { "400", "proc4", "200", "100",
|
|
|
|
+ "100", "400000" });
|
|
|
|
+ procInfos[4] =
|
|
|
|
+ new ProcessStatInfo(new String[] { "500", "proc5", "400", "100",
|
|
|
|
+ "100", "400000" });
|
|
|
|
+ procInfos[5] =
|
|
|
|
+ new ProcessStatInfo(new String[] { "600", "proc6", "1", "1", "1",
|
|
|
|
+ "400000" });
|
|
|
|
+
|
|
|
|
+ String[] cmdLines = new String[numProcesses];
|
|
|
|
+ cmdLines[0] = "proc1 arg1 arg2";
|
|
|
|
+ cmdLines[1] = "proc2 arg3 arg4";
|
|
|
|
+ cmdLines[2] = "proc3 arg5 arg6";
|
|
|
|
+ cmdLines[3] = "proc4 arg7 arg8";
|
|
|
|
+ cmdLines[4] = "proc5 arg9 arg10";
|
|
|
|
+ cmdLines[5] = "proc6 arg11 arg12";
|
|
|
|
+
|
|
|
|
+ writeStatFiles(procfsRootDir, pids, procInfos);
|
|
|
|
+ writeCmdLineFiles(procfsRootDir, pids, cmdLines);
|
|
|
|
+
|
|
|
|
+ ProcfsBasedProcessTree processTree =
|
|
|
|
+ new ProcfsBasedProcessTree("100", procfsRootDir.getAbsolutePath());
|
|
|
|
+ // build the process tree.
|
|
|
|
+ processTree.getProcessTree();
|
|
|
|
+
|
|
|
|
+ // Get the process-tree dump
|
|
|
|
+ String processTreeDump = processTree.getProcessTreeDump();
|
|
|
|
+
|
|
|
|
+ LOG.info("Process-tree dump follows: \n" + processTreeDump);
|
|
|
|
+ assertTrue("Process-tree dump doesn't start with a proper header",
|
|
|
|
+ processTreeDump.startsWith("\t|- PID PPID PGRPID SESSID CMD_NAME "
|
|
|
|
+ + "VMEM_USAGE(BYTES) FULL_CMD_LINE\n"));
|
|
|
|
+ for (int i = 0; i < 5; i++) {
|
|
|
|
+ ProcessStatInfo p = procInfos[i];
|
|
|
|
+ assertTrue(
|
|
|
|
+ "Process-tree dump doesn't contain the cmdLineDump of process "
|
|
|
|
+ + p.pid, processTreeDump.contains("\t|- " + p.pid + " "
|
|
|
|
+ + p.ppid + " " + p.pgrpId + " " + p.session + " (" + p.name
|
|
|
|
+ + ") " + p.vmem + " " + cmdLines[i]));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 600 should not be in the dump
|
|
|
|
+ ProcessStatInfo p = procInfos[5];
|
|
|
|
+ assertFalse(
|
|
|
|
+ "Process-tree dump shouldn't contain the cmdLineDump of process "
|
|
|
|
+ + p.pid, processTreeDump.contains("\t|- " + p.pid + " " + p.ppid
|
|
|
|
+ + " " + p.pgrpId + " " + p.session + " (" + p.name + ") "
|
|
|
|
+ + p.vmem + " " + cmdLines[5]));
|
|
|
|
+ } finally {
|
|
|
|
+ FileUtil.fullyDelete(procfsRootDir);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Create a directory to mimic the procfs file system's root.
|
|
* Create a directory to mimic the procfs file system's root.
|
|
* @param procfsRootDir root directory to create.
|
|
* @param procfsRootDir root directory to create.
|
|
@@ -398,7 +502,9 @@ public class TestProcfsBasedProcessTree extends TestCase {
|
|
public static void writeStatFiles(File procfsRootDir, String[] pids,
|
|
public static void writeStatFiles(File procfsRootDir, String[] pids,
|
|
ProcessStatInfo[] procs) throws IOException {
|
|
ProcessStatInfo[] procs) throws IOException {
|
|
for (int i=0; i<pids.length; i++) {
|
|
for (int i=0; i<pids.length; i++) {
|
|
- File statFile = new File(new File(procfsRootDir, pids[i]), "stat");
|
|
|
|
|
|
+ File statFile =
|
|
|
|
+ new File(new File(procfsRootDir, pids[i]),
|
|
|
|
+ ProcfsBasedProcessTree.PROCFS_STAT_FILE);
|
|
BufferedWriter bw = null;
|
|
BufferedWriter bw = null;
|
|
try {
|
|
try {
|
|
FileWriter fw = new FileWriter(statFile);
|
|
FileWriter fw = new FileWriter(statFile);
|
|
@@ -414,4 +520,26 @@ public class TestProcfsBasedProcessTree extends TestCase {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ private static void writeCmdLineFiles(File procfsRootDir, String[] pids,
|
|
|
|
+ String[] cmdLines)
|
|
|
|
+ throws IOException {
|
|
|
|
+ for (int i = 0; i < pids.length; i++) {
|
|
|
|
+ File statFile =
|
|
|
|
+ new File(new File(procfsRootDir, pids[i]),
|
|
|
|
+ ProcfsBasedProcessTree.PROCFS_CMDLINE_FILE);
|
|
|
|
+ BufferedWriter bw = null;
|
|
|
|
+ try {
|
|
|
|
+ bw = new BufferedWriter(new FileWriter(statFile));
|
|
|
|
+ bw.write(cmdLines[i]);
|
|
|
|
+ LOG.info("wrote command-line file for " + pids[i] + " with contents: "
|
|
|
|
+ + cmdLines[i]);
|
|
|
|
+ } finally {
|
|
|
|
+ // not handling exception - will throw an error and fail the test.
|
|
|
|
+ if (bw != null) {
|
|
|
|
+ bw.close();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|