001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.reef.runtime.common.launch; 020 021import org.apache.reef.runtime.common.evaluator.PIDStoreStartHandler; 022import org.apache.reef.runtime.common.launch.parameters.ClockConfigurationPath; 023import org.apache.reef.runtime.common.launch.parameters.ErrorHandlerRID; 024import org.apache.reef.runtime.common.launch.parameters.LaunchID; 025import org.apache.reef.tang.*; 026import org.apache.reef.tang.annotations.Name; 027import org.apache.reef.tang.annotations.NamedParameter; 028import org.apache.reef.tang.annotations.Parameter; 029import org.apache.reef.tang.formats.ConfigurationSerializer; 030import org.apache.reef.util.REEFVersion; 031import org.apache.reef.wake.profiler.WakeProfiler; 032import org.apache.reef.wake.remote.RemoteConfiguration; 033import org.apache.reef.wake.time.Clock; 034 035import javax.inject.Inject; 036import java.io.File; 037import java.io.FileNotFoundException; 038import java.io.IOException; 039import java.util.logging.Level; 040import java.util.logging.Logger; 041 042/** 043 * This encapsulates processes started by REEF. 044 */ 045public final class LaunchClass implements AutoCloseable, Runnable { 046 047 private static final Logger LOG = Logger.getLogger(LaunchClass.class.getName()); 048 private final String launchID; 049 private final String errorHandlerID; 050 private final String evaluatorConfigurationPath; 051 private final boolean isProfilingEnabled; 052 private final REEFErrorHandler errorHandler; 053 private final ConfigurationSerializer configurationSerializer; 054 private WakeProfiler profiler; 055 056 @Inject 057 LaunchClass(final REEFUncaughtExceptionHandler uncaughtExceptionHandler, 058 final REEFErrorHandler errorHandler, 059 final @Parameter(LaunchID.class) String launchID, 060 final @Parameter(ErrorHandlerRID.class) String errorHandlerID, 061 final @Parameter(ClockConfigurationPath.class) String evaluatorConfigurationPath, 062 final @Parameter(ProfilingEnabled.class) boolean enableProfiling, 063 final ConfigurationSerializer configurationSerializer, 064 final REEFVersion reefVersion) { 065 reefVersion.logVersion(); 066 this.launchID = launchID; 067 this.errorHandlerID = errorHandlerID; 068 this.evaluatorConfigurationPath = evaluatorConfigurationPath; 069 this.isProfilingEnabled = enableProfiling; 070 this.errorHandler = errorHandler; 071 this.configurationSerializer = configurationSerializer; 072 073 074 // Registering a default exception handler. It sends every exception to the upstream RemoteManager 075 Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler); 076 077 078 if (isProfilingEnabled) { 079 this.profiler = new WakeProfiler(); 080 ProfilingStopHandler.setProfiler(profiler); // TODO: This probably should be bound via Tang. 081 } 082 LOG.log(Level.FINE, "Instantiated LaunchClass"); 083 } 084 085 /** 086 * Loads the client and resource manager configuration files from disk. 087 */ 088 private Configuration getClockConfiguration() { 089 return Configurations.merge(readConfigurationFromDisk(), getStaticClockConfiguration()); 090 } 091 092 093 private Configuration readConfigurationFromDisk() { 094 LOG.log(Level.FINEST, "Loading configuration file: {0}", this.evaluatorConfigurationPath); 095 096 final File evaluatorConfigFile = new File(this.evaluatorConfigurationPath); 097 098 if (!evaluatorConfigFile.exists()) { 099 final String message = "The configuration file " + this.evaluatorConfigurationPath + 100 "doesn't exist. This points to an issue in the job submission."; 101 fail(message, new FileNotFoundException()); 102 throw new RuntimeException(message); 103 } else if (!evaluatorConfigFile.canRead()) { 104 final String message = "The configuration file " + this.evaluatorConfigurationPath + " exists, but can't be read"; 105 fail(message, new IOException()); 106 throw new RuntimeException(message); 107 } else { 108 try { 109 return this.configurationSerializer.fromFile(evaluatorConfigFile); 110 } catch (final IOException e) { 111 final String message = "Unable to parse the configuration file " + this.evaluatorConfigurationPath; 112 fail(message, e); 113 throw new RuntimeException(message, e); 114 } 115 } 116 } 117 118 /** 119 * @return the part of the clock configuration *not* read from disk. 120 */ 121 private Configuration getStaticClockConfiguration() { 122 final JavaConfigurationBuilder builder = Tang.Factory.getTang().newConfigurationBuilder() 123 .bindNamedParameter(LaunchID.class, this.launchID) 124 .bindNamedParameter(ErrorHandlerRID.class, this.errorHandlerID) 125 .bindSetEntry(Clock.StartHandler.class, PIDStoreStartHandler.class) 126 .bindNamedParameter(RemoteConfiguration.ErrorHandler.class, REEFErrorHandler.class) 127 .bindNamedParameter(RemoteConfiguration.ManagerName.class, "REEF_LAUNCHER") 128 .bindNamedParameter(RemoteConfiguration.MessageCodec.class, REEFMessageCodec.class); 129 if (this.isProfilingEnabled) { 130 builder.bindSetEntry(Clock.StopHandler.class, ProfilingStopHandler.class); 131 } 132 return builder.build(); 133 } 134 135 /** 136 * Instantiates the clock. 137 * 138 * @return a clock object. 139 */ 140 private Clock getClock() { 141 try { 142 final Injector clockInjector = Tang.Factory.getTang().newInjector(this.getClockConfiguration()); 143 if (isProfilingEnabled) { 144 clockInjector.bindAspect(profiler); 145 } 146 return clockInjector.getInstance(Clock.class); 147 } catch (final Throwable ex) { 148 fail("Unable to instantiate the clock", ex); 149 throw new RuntimeException("Unable to instantiate the clock", ex); 150 } 151 } 152 153 /** 154 * Starts the Clock. 155 * This blocks until the clock returns. 156 */ 157 @Override 158 public void run() { 159 LOG.entering(this.getClass().getName(), "run", "Starting the clock"); 160 try { 161 this.getClock().run(); 162 } catch (final Throwable t) { 163 fail("Fatal exception while executing the clock", t); 164 } 165 LOG.exiting(this.getClass().getName(), "run", "Clock terminated"); 166 } 167 168 /** 169 * Closes the remote manager managed by this class. 170 * 171 * @throws Exception 172 */ 173 @Override 174 public void close() throws Exception { 175 LOG.entering(this.getClass().getName(), "close"); 176 this.errorHandler.close(); // Also closes the remoteManager 177 LOG.exiting(this.getClass().getName(), "close"); 178 } 179 180 private void fail(final String message, final Throwable throwable) { 181 this.errorHandler.onNext(new Exception(message, throwable)); 182 } 183 184 @NamedParameter(doc = "If true, profiling will be enabled", short_name = "profiling", default_value = "false") 185 public final static class ProfilingEnabled implements Name<Boolean> { 186 } 187}