package net.openhft.chronicle.engine; import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.engine.api.EngineReplication; import net.openhft.chronicle.engine.api.map.KeyValueStore; import net.openhft.chronicle.engine.api.map.MapView; import net.openhft.chronicle.engine.api.tree.Asset; import net.openhft.chronicle.engine.cfg.EngineCfg; import net.openhft.chronicle.engine.fs.Clusters; import net.openhft.chronicle.engine.fs.EngineCluster; import net.openhft.chronicle.engine.fs.EngineHostDetails; import net.openhft.chronicle.engine.map.CMap2EngineReplicator; import net.openhft.chronicle.engine.map.ChronicleMapKeyValueStore; import net.openhft.chronicle.engine.map.VanillaMapView; import net.openhft.chronicle.engine.query.QueueConfig; import net.openhft.chronicle.engine.server.ServerEndpoint; import net.openhft.chronicle.engine.tree.TopologicalEvent; import net.openhft.chronicle.engine.tree.VanillaAssetTree; import net.openhft.chronicle.network.NetworkStats; import net.openhft.chronicle.network.NetworkStatsListener; import net.openhft.chronicle.network.cluster.HostDetails; import net.openhft.chronicle.wire.TextWire; 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 static net.openhft.chronicle.core.onoes.PrintExceptionHandler.WARN; import static net.openhft.chronicle.engine.api.tree.RequestContext.loadDefaultAliases; /** * @author Rob Austin. */ public class EngineInstance { static final Logger LOGGER = LoggerFactory.getLogger(EngineInstance.class); static { try { net.openhft.chronicle.core.Jvm.setExceptionsHandlers(WARN, WARN, null); loadDefaultAliases(); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } } public static VanillaAssetTree engineMain(final int hostId, final String yamlConfigFile) { try { @NotNull TextWire yaml = TextWire.fromFile(yamlConfigFile); @NotNull EngineCfg installable = (EngineCfg) yaml.readObject(); @NotNull final VanillaAssetTree tree = new VanillaAssetTree(hostId).forServer(false); @NotNull final Asset connectivityMap = tree.acquireAsset("/proc/connections/cluster/connectivity"); connectivityMap.addWrappingRule(MapView.class, "map directly to KeyValueStore", VanillaMapView::new, KeyValueStore.class); connectivityMap.addLeafRule(EngineReplication.class, "Engine replication holder", CMap2EngineReplicator::new); connectivityMap.addLeafRule(KeyValueStore.class, "KVS is Chronicle Map", (context, asset) -> new ChronicleMapKeyValueStore(context.cluster(firstClusterName(tree)), asset)); try { installable.install("/", tree); LOGGER.info("Engine started"); } catch (Exception e) { LOGGER.error("Error starting a component, stopping", e); tree.close(); } @Nullable final Clusters clusters = tree.root().getView(Clusters.class); if (clusters == null || clusters.size() == 0) { Jvm.warn().on(EngineInstance.class, "cluster not found"); return null; } if (clusters.size() != 1) { Jvm.warn().on(EngineInstance.class, "unambiguous cluster, you have " + clusters.size() + "" + " clusters which one do you want to use?"); return null; } final EngineCluster engineCluster = clusters.firstCluster(); final HostDetails hostDetails = engineCluster.findHostDetails(hostId); final String connectUri = hostDetails.connectUri(); engineCluster.clusterContext().assetRoot(tree.root()); final NetworkStatsListener networkStatsListener = engineCluster.clusterContext() .networkStatsListenerFactory() .apply(engineCluster.clusterContext()); @NotNull final ServerEndpoint serverEndpoint = new ServerEndpoint(connectUri, tree, networkStatsListener); // we add this as close will get called when the asset tree is closed tree.root().addView(ServerEndpoint.class, serverEndpoint); tree.registerSubscriber("", TopologicalEvent.class, e -> LOGGER.info("Tree change " + e)); // the reason that we have to do this is to ensure that the network stats are // replicated between all hosts, if you don't acquire a queue it wont exist and so // will not act as a slave in replication for (@NotNull EngineHostDetails engineHostDetails : engineCluster.hostDetails()) { final int id = engineHostDetails .hostId(); Asset asset = tree.acquireAsset("/proc/connections/cluster/throughput/" + id); // sets the master of each of the queues asset.addView(new QueueConfig(x -> id, false, null, WireType.BINARY)); tree.acquireQueue("/proc/connections/cluster/throughput/" + id, String.class, NetworkStats.class, engineCluster.clusterName()); } return tree; } catch (Exception e) { throw Jvm.rethrow(e); } } /** * @return the first cluster name */ static String firstClusterName(@NotNull VanillaAssetTree tree) { @Nullable final Clusters clusters = tree.root().getView(Clusters.class); if (clusters == null) return ""; final EngineCluster engineCluster = clusters.firstCluster(); if (engineCluster == null) return ""; return engineCluster.clusterName(); } }