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.wake.remote.impl; 020 021import org.apache.reef.tang.annotations.Parameter; 022import org.apache.reef.wake.EStage; 023import org.apache.reef.wake.EventHandler; 024import org.apache.reef.wake.impl.StageManager; 025import org.apache.reef.wake.remote.*; 026import org.apache.reef.wake.remote.address.LocalAddressProvider; 027import org.apache.reef.wake.remote.ports.RangeTcpPortProvider; 028import org.apache.reef.wake.remote.ports.TcpPortProvider; 029import org.apache.reef.wake.remote.transport.Transport; 030import org.apache.reef.wake.remote.transport.TransportFactory; 031import org.apache.reef.wake.remote.transport.netty.NettyMessagingTransport; 032 033import javax.inject.Inject; 034import java.net.InetSocketAddress; 035import java.util.concurrent.ExecutorService; 036import java.util.concurrent.Executors; 037import java.util.concurrent.TimeUnit; 038import java.util.concurrent.atomic.AtomicBoolean; 039import java.util.concurrent.atomic.AtomicInteger; 040import java.util.logging.Level; 041import java.util.logging.Logger; 042 043/** 044 * Default remote manager implementation. 045 */ 046public class DefaultRemoteManagerImplementation implements RemoteManager { 047 048 private static final Logger LOG = Logger.getLogger(HandlerContainer.class.getName()); 049 050 private static final AtomicInteger COUNTER = new AtomicInteger(0); 051 052 /** 053 * The timeout used for the execute running in close(). 054 */ 055 private static final long CLOSE_EXECUTOR_TIMEOUT = 10000; //ms 056 private final AtomicBoolean closed = new AtomicBoolean(false); 057 private final String name; 058 private final Transport transport; 059 private final RemoteSenderStage reSendStage; 060 private final EStage<TransportEvent> reRecvStage; 061 private final HandlerContainer handlerContainer; 062 private final RemoteSeqNumGenerator seqGen = new RemoteSeqNumGenerator(); 063 private RemoteIdentifier myIdentifier; 064 /** 065 * Indicates a hostname that isn't set or known. 066 */ 067 public static final String UNKNOWN_HOST_NAME = NettyMessagingTransport.UNKNOWN_HOST_NAME; 068 069 /** 070 * @deprecated have an instance injected instead. 071 */ 072 @Deprecated 073 @Inject 074 public <T> DefaultRemoteManagerImplementation( 075 @Parameter(RemoteConfiguration.ManagerName.class) final String name, 076 @Parameter(RemoteConfiguration.HostAddress.class) final String hostAddress, 077 @Parameter(RemoteConfiguration.Port.class) final int listeningPort, 078 @Parameter(RemoteConfiguration.MessageCodec.class) final Codec<T> codec, 079 @Parameter(RemoteConfiguration.ErrorHandler.class) final EventHandler<Throwable> errorHandler, 080 @Parameter(RemoteConfiguration.OrderingGuarantee.class) final boolean orderingGuarantee, 081 @Parameter(RemoteConfiguration.NumberOfTries.class) final int numberOfTries, 082 @Parameter(RemoteConfiguration.RetryTimeout.class) final int retryTimeout, 083 final LocalAddressProvider localAddressProvider, 084 final TransportFactory tpFactory) { 085 this(name, hostAddress, listeningPort, codec, errorHandler, orderingGuarantee, numberOfTries, retryTimeout, 086 localAddressProvider, tpFactory, RangeTcpPortProvider.Default); 087 } 088 089 @Inject 090 private <T> DefaultRemoteManagerImplementation( 091 @Parameter(RemoteConfiguration.ManagerName.class) final String name, 092 @Parameter(RemoteConfiguration.HostAddress.class) final String hostAddress, 093 @Parameter(RemoteConfiguration.Port.class) final int listeningPort, 094 @Parameter(RemoteConfiguration.MessageCodec.class) final Codec<T> codec, 095 @Parameter(RemoteConfiguration.ErrorHandler.class) final EventHandler<Throwable> errorHandler, 096 @Parameter(RemoteConfiguration.OrderingGuarantee.class) final boolean orderingGuarantee, 097 @Parameter(RemoteConfiguration.NumberOfTries.class) final int numberOfTries, 098 @Parameter(RemoteConfiguration.RetryTimeout.class) final int retryTimeout, 099 final LocalAddressProvider localAddressProvider, 100 final TransportFactory tpFactory, 101 final TcpPortProvider tcpPortProvider) { 102 103 this.name = name; 104 this.handlerContainer = new HandlerContainer<>(name, codec); 105 106 this.reRecvStage = orderingGuarantee ? 107 new OrderedRemoteReceiverStage(this.handlerContainer, errorHandler) : 108 new RemoteReceiverStage(this.handlerContainer, errorHandler, 10); 109 110 this.transport = tpFactory.newInstance( 111 hostAddress, listeningPort, this.reRecvStage, this.reRecvStage, numberOfTries, retryTimeout, 112 tcpPortProvider); 113 114 this.handlerContainer.setTransport(this.transport); 115 116 this.myIdentifier = new SocketRemoteIdentifier( 117 (InetSocketAddress) this.transport.getLocalAddress()); 118 119 this.reSendStage = new RemoteSenderStage(codec, this.transport, 10); 120 121 StageManager.instance().register(this); 122 LOG.log(Level.FINEST, "RemoteManager {0} instantiated id {1} counter {2} listening on {3}:{4}. " + 123 "Binding address provided by {5}", 124 new Object[]{this.name, this.myIdentifier, COUNTER.incrementAndGet(), 125 this.transport.getLocalAddress().toString(), 126 this.transport.getListeningPort(), localAddressProvider} 127 ); 128 } 129 130 131 /** 132 * Returns a proxy event handler for a remote identifier and a message type. 133 */ 134 @Override 135 public <T> EventHandler<T> getHandler( 136 final RemoteIdentifier destinationIdentifier, final Class<? extends T> messageType) { 137 138 if (LOG.isLoggable(Level.FINE)) { 139 LOG.log(Level.FINE, "RemoteManager: {0} destinationIdentifier: {1} messageType: {2}", 140 new Object[]{this.name, destinationIdentifier, messageType.getName()}); 141 } 142 143 return new ProxyEventHandler<>(this.myIdentifier, destinationIdentifier, 144 "default", this.reSendStage.<T>getHandler(), this.seqGen); 145 } 146 147 /** 148 * Registers an event handler for a remote identifier and a message type and. 149 * returns a subscription 150 */ 151 @Override 152 public <T, U extends T> AutoCloseable registerHandler( 153 final RemoteIdentifier sourceIdentifier, 154 final Class<U> messageType, final EventHandler<T> theHandler) { 155 if (LOG.isLoggable(Level.FINE)) { 156 LOG.log(Level.FINE, "RemoteManager: {0} remoteid: {1} messageType: {2} handler: {3}", 157 new Object[]{this.name, sourceIdentifier, messageType.getName(), 158 theHandler.getClass().getName()}); 159 } 160 return this.handlerContainer.registerHandler(sourceIdentifier, messageType, theHandler); 161 } 162 163 /** 164 * Registers an event handler for a message type and returns a subscription. 165 */ 166 @Override 167 public <T, U extends T> AutoCloseable registerHandler( 168 final Class<U> messageType, final EventHandler<RemoteMessage<T>> theHandler) { 169 if (LOG.isLoggable(Level.FINE)) { 170 LOG.log(Level.FINE, "RemoteManager: {0} messageType: {1} handler: {2}", 171 new Object[]{this.name, messageType.getName(), theHandler.getClass().getName()}); 172 } 173 return this.handlerContainer.registerHandler(messageType, theHandler); 174 } 175 176 /** 177 * Registers an exception handler and returns a subscription. 178 */ 179 @Override 180 public AutoCloseable registerErrorHandler(final EventHandler<Exception> theHandler) { 181 if (LOG.isLoggable(Level.FINE)) { 182 LOG.log(Level.FINE, "RemoteManager: {0} handler: {1}", 183 new Object[]{this.name, theHandler.getClass().getName()}); 184 } 185 return this.handlerContainer.registerErrorHandler(theHandler); 186 } 187 188 /** 189 * Returns my identifier. 190 */ 191 @Override 192 public RemoteIdentifier getMyIdentifier() { 193 return this.myIdentifier; 194 } 195 196 @Override 197 public void close() { 198 if (closed.compareAndSet(false, true)) { 199 200 LOG.log(Level.FINE, "RemoteManager: {0} Closing remote manager id: {1}", 201 new Object[]{this.name, this.myIdentifier}); 202 203 final Runnable closeRunnable = new Runnable() { 204 @Override 205 public void run() { 206 try { 207 LOG.log(Level.FINE, "Closing sender stage {0}", myIdentifier); 208 reSendStage.close(); 209 LOG.log(Level.FINE, "Closed the remote sender stage"); 210 } catch (final Exception e) { 211 LOG.log(Level.SEVERE, "Unable to close the remote sender stage", e); 212 } 213 214 try { 215 LOG.log(Level.FINE, "Closing transport {0}", myIdentifier); 216 transport.close(); 217 LOG.log(Level.FINE, "Closed the transport"); 218 } catch (final Exception e) { 219 LOG.log(Level.SEVERE, "Unable to close the transport.", e); 220 } 221 222 try { 223 LOG.log(Level.FINE, "Closing receiver stage {0}", myIdentifier); 224 reRecvStage.close(); 225 LOG.log(Level.FINE, "Closed the remote receiver stage"); 226 } catch (final Exception e) { 227 LOG.log(Level.SEVERE, "Unable to close the remote receiver stage", e); 228 } 229 } 230 231 }; 232 233 final ExecutorService closeExecutor = Executors.newSingleThreadExecutor(); 234 closeExecutor.submit(closeRunnable); 235 closeExecutor.shutdown(); 236 if (!closeExecutor.isShutdown()) { 237 LOG.log(Level.SEVERE, "close executor did not shutdown properly."); 238 } 239 240 final long endTime = System.currentTimeMillis() + CLOSE_EXECUTOR_TIMEOUT; 241 while (!closeExecutor.isTerminated()) { 242 try { 243 final long waitTime = endTime - System.currentTimeMillis(); 244 closeExecutor.awaitTermination(waitTime, TimeUnit.MILLISECONDS); 245 } catch (final InterruptedException e) { 246 LOG.log(Level.FINE, "Interrupted", e); 247 } 248 } 249 250 if (closeExecutor.isTerminated()) { 251 LOG.log(Level.FINE, "Close executor terminated properly."); 252 } else { 253 LOG.log(Level.SEVERE, "Close executor did not terminate properly."); 254 } 255 } 256 } 257}