/* * Copyright 2016 higherfrequencytrading.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package net.openhft.chronicle.engine.cfg; import net.openhft.chronicle.core.annotation.UsedViaReflection; import net.openhft.chronicle.core.threads.EventLoop; import net.openhft.chronicle.core.util.ThrowingFunction; import net.openhft.chronicle.engine.HeartbeatHandler; import net.openhft.chronicle.engine.api.tree.Asset; import net.openhft.chronicle.engine.fs.EngineConnectionManager; import net.openhft.chronicle.engine.server.internal.EngineNetworkStatsListener; import net.openhft.chronicle.engine.server.internal.EngineWireHandler; import net.openhft.chronicle.engine.server.internal.EngineWireNetworkContext; import net.openhft.chronicle.engine.server.internal.UberHandler; import net.openhft.chronicle.engine.tree.HostIdentifier; import net.openhft.chronicle.network.*; import net.openhft.chronicle.network.api.TcpHandler; import net.openhft.chronicle.network.api.session.SessionDetailsProvider; import net.openhft.chronicle.network.cluster.ClusterContext; import net.openhft.chronicle.network.cluster.HostIdConnectionStrategy; import net.openhft.chronicle.network.connection.VanillaWireOutPublisher; import net.openhft.chronicle.wire.WireIn; import net.openhft.chronicle.wire.WireType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.function.Function; import static net.openhft.chronicle.network.NetworkStatsListener.notifyHostPort; /** * @author Rob Austin. */ public class EngineClusterContext extends ClusterContext { private static final Logger LOG = LoggerFactory.getLogger(EngineClusterContext.class); Asset assetRoot; private byte localIdentifier; @NotNull private NetworkStatsListener defaultNetworkStatsListener = new NetworkStatsListener() { String host; long port; @Override public void close() { LOG.info("writeKBps=0" + ", readKBps=0" + ", socketPollCountPerSecond=0" + ", host=" + host + ", port=" + port + ", isConnected=false"); } @Override public void networkContext(NetworkContext networkContext) { } @Override public void onNetworkStats(long writeBps, long readBps, long socketPollCountPerSecond) { LOG.info("writeKBps=" + writeBps / 1000 + ", readKBps=" + readBps / 1000 + ", socketPollCountPerSecond=" + socketPollCountPerSecond + ", host=" + host + ", port=" + port + ", isConnected=true"); } @Override public void onHostPort(String hostName, int port) { host = hostName; this.port = port; } @Override public void onRoundTripLatency(long nanosecondLatency) { } }; @UsedViaReflection private EngineClusterContext(@NotNull WireIn w) { super(w); } public EngineClusterContext() { super(); } @Nullable public ThrowingFunction<NetworkContext, TcpEventHandler, IOException> tcpEventHandlerFactory() { return (networkContext) -> { @NotNull final EngineWireNetworkContext nc = (EngineWireNetworkContext) networkContext; if (nc.isAcceptor()) nc.wireOutPublisher(new VanillaWireOutPublisher(WireType.TEXT)); // TODO make configurable. networkContext.serverThreadingStrategy(ServerThreadingStrategy.CONCURRENT); @NotNull final TcpEventHandler handler = new TcpEventHandler(networkContext); @NotNull final Function<Object, TcpHandler> consumer = o -> { if (o instanceof SessionDetailsProvider) { @NotNull final SessionDetailsProvider sessionDetails = (SessionDetailsProvider) o; nc.heartbeatTimeoutMs(heartbeatTimeoutMs()); nc.sessionDetails(sessionDetails); nc.wireType(sessionDetails.wireType()); @Nullable final WireType wireType = nc.sessionDetails().wireType(); if (wireType != null) nc.wireOutPublisher().wireType(wireType); return new EngineWireHandler(); } else if (o instanceof TcpHandler) return (TcpHandler) o; throw new UnsupportedOperationException("not supported class=" + o.getClass()); }; if (nc.networkStatsListener() == null) nc.networkStatsListener(defaultNetworkStatsListener); final NetworkStatsListener nl = nc.networkStatsListener(); if (nl != null) notifyHostPort(nc.socketChannel(), nl); @Nullable final Function<EngineWireNetworkContext, TcpHandler> f = x -> new HeaderTcpHandler<>(handler, consumer, x); @NotNull final WireTypeSniffingTcpHandler sniffer = new WireTypeSniffingTcpHandler<>(handler, f); handler.tcpHandler(sniffer); return handler; }; } public Asset assetRoot() { return assetRoot; } @NotNull public EngineClusterContext assetRoot(@NotNull Asset assetRoot) { this.assetRoot = assetRoot; localIdentifier = HostIdentifier.localIdentifier(assetRoot); localIdentifier(localIdentifier); eventLoop(assetRoot.findOrCreateView(EventLoop.class)); return this; } @Override public void defaults() { wireType(WireType.TEXT); handlerFactory(new UberHandler.Factory()); wireOutPublisherFactory(new VanillaWireOutPublisherFactory()); networkContextFactory(new EngineWireNetworkContext.Factory()); networkStatsListenerFactory(new EngineNetworkStatsListener.Factory()); connectionEventHandler(new EngineConnectionManager.Factory()); heartbeatFactory(new HeartbeatHandler.Factory()); heartbeatTimeoutMs(5_000L); heartbeatIntervalMs(1_000L); connectionStrategy(new HostIdConnectionStrategy()); serverThreadingStrategy(ServerThreadingStrategy.SINGLE_THREADED); } }