/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.internal.processors.hadoop.taskexecutor.external.child;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URL;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteLogger;
import org.apache.ignite.internal.processors.hadoop.taskexecutor.external.HadoopProcessDescriptor;
import org.apache.ignite.internal.processors.hadoop.taskexecutor.external.communication.HadoopExternalCommunication;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteClosure;
import org.apache.ignite.logger.log4j.Log4JLogger;
import org.apache.ignite.marshaller.jdk.JdkMarshaller;
/**
* Hadoop external process base class.
*/
public class HadoopExternalProcessStarter {
/** Path to Log4j configuration file. */
public static final String DFLT_LOG4J_CONFIG = "config/ignite-log4j.xml";
/** Arguments. */
private Args args;
/** System out. */
private OutputStream out;
/** System err. */
private OutputStream err;
/**
* @param args Parsed arguments.
*/
public HadoopExternalProcessStarter(Args args) {
this.args = args;
}
/**
* @param cmdArgs Process arguments.
*/
public static void main(String[] cmdArgs) {
try {
Args args = arguments(cmdArgs);
new HadoopExternalProcessStarter(args).run();
}
catch (Exception e) {
System.err.println("Failed");
System.err.println(e.getMessage());
e.printStackTrace(System.err);
}
}
/**
* Run the process.
*
* @throws Exception If failed.
*/
public void run() throws Exception {
File outputDir = outputDirectory();
initializeStreams(outputDir);
ExecutorService msgExecSvc = Executors.newFixedThreadPool(
Integer.getInteger("MSG_THREAD_POOL_SIZE", Runtime.getRuntime().availableProcessors() * 2));
IgniteLogger log = logger(outputDir);
HadoopExternalCommunication comm = new HadoopExternalCommunication(
args.nodeId,
args.childProcId,
new JdkMarshaller(),
log,
msgExecSvc,
"external",
args.workDir
);
comm.start();
HadoopProcessDescriptor nodeDesc = new HadoopProcessDescriptor(args.nodeId, args.parentProcId);
nodeDesc.address(args.addr);
nodeDesc.tcpPort(args.tcpPort);
nodeDesc.sharedMemoryPort(args.shmemPort);
HadoopChildProcessRunner runner = new HadoopChildProcessRunner();
runner.start(comm, nodeDesc, msgExecSvc, log);
System.err.println("Started");
System.err.flush();
System.setOut(new PrintStream(out));
System.setErr(new PrintStream(err));
}
/**
* @param outputDir Directory for process output.
* @throws Exception If failed.
*/
private void initializeStreams(File outputDir) throws Exception {
out = new FileOutputStream(new File(outputDir, args.childProcId + ".out"));
err = new FileOutputStream(new File(outputDir, args.childProcId + ".err"));
}
/**
* @return Path to output directory.
* @throws IOException If failed.
*/
private File outputDirectory() throws IOException {
File f = new File(args.out);
if (!f.exists()) {
if (!f.mkdirs())
throw new IOException("Failed to create output directory: " + args.out);
}
else {
if (f.isFile())
throw new IOException("Output directory is a file: " + args.out);
}
return f;
}
/**
* @param outputDir Directory for process output.
* @return Logger.
*/
private IgniteLogger logger(final File outputDir) {
final URL url = U.resolveIgniteUrl(DFLT_LOG4J_CONFIG);
Log4JLogger logger;
try {
logger = url != null ? new Log4JLogger(url) : new Log4JLogger(true);
}
catch (IgniteCheckedException e) {
System.err.println("Failed to create URL-based logger. Will use default one.");
e.printStackTrace();
logger = new Log4JLogger(true);
}
logger.updateFilePath(new IgniteClosure<String, String>() {
@Override public String apply(String s) {
return new File(outputDir, args.childProcId + ".log").getAbsolutePath();
}
});
return logger;
}
/**
* @param processArgs Process arguments.
* @return Child process instance.
*/
private static Args arguments(String[] processArgs) throws Exception {
Args args = new Args();
for (int i = 0; i < processArgs.length; i++) {
String arg = processArgs[i];
switch (arg) {
case "-cpid": {
if (i == processArgs.length - 1)
throw new Exception("Missing process ID for '-cpid' parameter");
String procIdStr = processArgs[++i];
args.childProcId = UUID.fromString(procIdStr);
break;
}
case "-ppid": {
if (i == processArgs.length - 1)
throw new Exception("Missing process ID for '-ppid' parameter");
String procIdStr = processArgs[++i];
args.parentProcId = UUID.fromString(procIdStr);
break;
}
case "-nid": {
if (i == processArgs.length - 1)
throw new Exception("Missing node ID for '-nid' parameter");
String nodeIdStr = processArgs[++i];
args.nodeId = UUID.fromString(nodeIdStr);
break;
}
case "-addr": {
if (i == processArgs.length - 1)
throw new Exception("Missing node address for '-addr' parameter");
args.addr = processArgs[++i];
break;
}
case "-tport": {
if (i == processArgs.length - 1)
throw new Exception("Missing tcp port for '-tport' parameter");
args.tcpPort = Integer.parseInt(processArgs[++i]);
break;
}
case "-sport": {
if (i == processArgs.length - 1)
throw new Exception("Missing shared memory port for '-sport' parameter");
args.shmemPort = Integer.parseInt(processArgs[++i]);
break;
}
case "-out": {
if (i == processArgs.length - 1)
throw new Exception("Missing output folder name for '-out' parameter");
args.out = processArgs[++i];
break;
}
case "-wd": {
if (i == processArgs.length - 1)
throw new Exception("Missing work folder name for '-wd' parameter");
args.workDir = processArgs[++i];
break;
}
}
}
return args;
}
/**
* Execution arguments.
*/
private static class Args {
/** Process ID. */
private UUID childProcId;
/** Process ID. */
private UUID parentProcId;
/** Process ID. */
private UUID nodeId;
/** Node address. */
private String addr;
/** TCP port */
private int tcpPort;
/** Shmem port. */
private int shmemPort = -1;
/** Output folder. */
private String out;
/** Work directory. */
private String workDir;
}
}