package org.radargun.service; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Paths; import java.util.regex.Pattern; import org.radargun.utils.TimeService; import org.radargun.utils.Utils; /** * Parent for Spark's Master & Worker lifecycles * * @author Matej Cimbora */ public abstract class AbstractSparkLifecycle extends ProcessLifecycle<AbstractSparkService> { public AbstractSparkLifecycle(AbstractSparkService service) { super(service); } protected void startInternal() { service.registerAction(getStartPattern(), m -> { long end = TimeService.currentTimeMillis() + service.logCreationTimeout; while (TimeService.currentTimeMillis() <= end) { String matchedString = m.group(); String fileName = matchedString.substring(matchedString.lastIndexOf("/")); try { FileInputStream fileInputStream = new FileInputStream(Paths.get(service.home, "logs", fileName).toFile()); getOutputReader().setStream(fileInputStream); return; } catch (FileNotFoundException e) { log.error("Log file not created yet"); Utils.sleep(1000); continue; } } throw new IllegalStateException("Failed to attach reader to log file"); }); super.startInternal(); } @Override public String getProcessId(Process process) { long end = TimeService.currentTimeMillis() + service.startupProcessTimeout; while (process.isAlive() && TimeService.currentTimeMillis() <= end) { try { Thread.sleep(500); } catch (InterruptedException e) { log.error("Interrupted while waiting for start process to finish ", e); Thread.currentThread().interrupt(); } } File[] pidFiles = FileSystems.getDefault().getPath(service.home, "pids").toFile().listFiles(new PidFileNameFilter()); if (pidFiles.length != 1) { log.error("Multiple or no PID files containing " + service.getPidFileIdent() + " found, something has gone wrong"); return super.getProcessId(process); } byte[] buffer; try { buffer = Files.readAllBytes(pidFiles[0].toPath()); } catch (IOException e) { log.error("Error reading PID file" + pidFiles[0].getName(), e); return super.getProcessId(process); } return new String(buffer).trim(); } private class PidFileNameFilter implements FilenameFilter { public boolean accept(File dir, String name) { return name.contains(service.getPidFileIdent()); } } @Override protected synchronized StreamReader getOutputReader() { if (outputReader == null) { outputReader = new FileOutputReader(line -> service.reportOutput(line)); } return outputReader; } @Override protected synchronized StreamReader getErrorReader() { if (errorReader == null) { errorReader = new FileOutputReader(line -> service.reportError(line)); } return errorReader; } private static class FileOutputReader extends ProcessOutputReader { public FileOutputReader(LineConsumer consumer) { super(consumer); } public void run() { String line; try { while (!isInterrupted()) { while ((line = reader.readLine()) != null) { consumer.consume(line); } try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { log.error("Failed to suspend the thread", e); } } } catch (IOException e) { log.error("Failed to read server output", e); } finally { try { reader.close(); } catch (IOException e) { log.error("Failed to close reader", e); } } } } protected abstract Pattern getStartPattern(); }