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