package net.openhft.chronicle.network; import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.core.io.IORuntimeException; import net.openhft.chronicle.core.util.Time; import net.openhft.chronicle.network.connection.FatalFailureMonitor; import net.openhft.chronicle.network.connection.SocketAddressSupplier; import net.openhft.chronicle.wire.WireIn; import net.openhft.chronicle.wire.Wires; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.InetSocketAddress; import java.nio.channels.SocketChannel; import java.util.concurrent.TimeUnit; import static net.openhft.chronicle.core.io.Closeable.closeQuietly; import static net.openhft.chronicle.network.connection.TcpChannelHub.TCP_BUFFER; /** * Loops through all the hosts:ports ( in order ) starting at the primary, till if finds a host that it can connect to. * If later, this successful connection is dropped, it will always return to the primary to begin attempting to find a successful connection, * If all the host:ports have been attempted since the last connection was established, no successful connection can be found, * then null is returned, and the fatalFailureMonitor.onFatalFailure() is triggered */ public class AlwaysStartOnPrimaryConnectionStrategy implements ConnectionStrategy { private static final Logger LOG = LoggerFactory.getLogger(AlwaysStartOnPrimaryConnectionStrategy.class); private int tcpBufferSize = Integer.getInteger("tcp.client.buffer.size", TCP_BUFFER); private int pausePeriodMs = Integer.getInteger("client.timeout", 500); public void readMarshallable(@NotNull WireIn wire) throws IORuntimeException { Wires.readMarshallable(this, wire, false); } @Nullable @Override public SocketChannel connect(@NotNull String name, @NotNull SocketAddressSupplier socketAddressSupplier, @Nullable NetworkStatsListener<? extends NetworkContext> networkStatsListener, boolean didLogIn, @Nullable FatalFailureMonitor fatalFailureMonitor) throws InterruptedException { if (socketAddressSupplier.get() == null || didLogIn) socketAddressSupplier.resetToPrimary(); else socketAddressSupplier.failoverToNextAddress(); for (; ; ) { SocketChannel socketChannel = null; try { @Nullable final InetSocketAddress socketAddress = socketAddressSupplier.get(); if (socketAddress == null) { Jvm.warn().on(AlwaysStartOnPrimaryConnectionStrategy.class, "failed to obtain socketAddress"); // at end if (isAtEnd(socketAddressSupplier)) { fatalFailureMonitor.onFatalFailure(name, "Failed to connect to any of these servers=" + socketAddressSupplier.remoteAddresses()); return null; } socketAddressSupplier.failoverToNextAddress(); continue; } socketChannel = openSocketChannel(socketAddress, tcpBufferSize, 500); if (socketChannel == null) { Jvm.debug().on(getClass(), "unable to connected to " + socketAddressSupplier.toString()); // at end if (isAtEnd(socketAddressSupplier)) { fatalFailureMonitor.onFatalFailure(name, "Failed to connect to any of these servers=" + socketAddressSupplier.remoteAddresses()); return null; } socketAddressSupplier.failoverToNextAddress(); continue; } Jvm.debug().on(getClass(), "successfully connected to " + socketAddressSupplier.toString()); if (networkStatsListener != null) networkStatsListener.onHostPort(socketAddress.getHostString(), socketAddress.getPort()); // success return socketChannel; } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (Throwable e) { //noinspection ConstantConditions if (socketChannel != null) closeQuietly(socketChannel); if (Jvm.isDebug()) LOG.info("", e); socketAddressSupplier.failoverToNextAddress(); Time.parkNanos(TimeUnit.MILLISECONDS.toNanos(pausePeriodMs)); } } } private boolean isAtEnd(SocketAddressSupplier socketAddressSupplier) { return socketAddressSupplier.size() - 1 == socketAddressSupplier.index(); } }