// Copyright 2016 Twitter. All rights reserved. // // 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 com.twitter.heron.simulator.utils; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.twitter.heron.api.generated.TopologyAPI; import com.twitter.heron.proto.system.HeronTuples; import com.twitter.heron.simulator.grouping.Grouping; /** * A stream could be consumed by many different downstream components by different grouping. * StreamConsumers is a class we could use to * fetch all task ids for all different components to send tuples to. */ public class StreamConsumers { private final List<Grouping> consumers = new ArrayList<>(); public StreamConsumers() { } /** * Populate the Stream Consumers for the whole topology given the topology protobuf. * * @param topology The given topology protobuf * @param componentToTaskIds the map of componentName to its list of taskIds in the topology * @return the populated stream consumers' map */ public static Map<TopologyAPI.StreamId, StreamConsumers> populateStreamConsumers( TopologyAPI.Topology topology, Map<String, List<Integer>> componentToTaskIds ) { // First get a map of (TopologyAPI.StreamId -> TopologyAPI.StreamSchema) Map<TopologyAPI.StreamId, TopologyAPI.StreamSchema> streamToSchema = new HashMap<>(); // Calculate spout's output stream for (TopologyAPI.Spout spout : topology.getSpoutsList()) { for (TopologyAPI.OutputStream outputStream : spout.getOutputsList()) { streamToSchema.put(outputStream.getStream(), outputStream.getSchema()); } } // Calculate bolt's output stream for (TopologyAPI.Bolt bolt : topology.getBoltsList()) { for (TopologyAPI.OutputStream outputStream : bolt.getOutputsList()) { streamToSchema.put(outputStream.getStream(), outputStream.getSchema()); } } // Then we would calculate the populated map of stream consumers Map<TopologyAPI.StreamId, StreamConsumers> populatedStreamConsumers = new HashMap<>(); // Only bolts could consume from input stream for (TopologyAPI.Bolt bolt : topology.getBoltsList()) { for (TopologyAPI.InputStream inputStream : bolt.getInputsList()) { TopologyAPI.StreamSchema schema = streamToSchema.get(inputStream.getStream()); String componentName = bolt.getComp().getName(); List<Integer> taskIds = componentToTaskIds.get(componentName); // Add component's task ids into stream consumers if (!populatedStreamConsumers.containsKey(inputStream.getStream())) { populatedStreamConsumers.put(inputStream.getStream(), new StreamConsumers()); } populatedStreamConsumers. get(inputStream.getStream()). newConsumer(inputStream, schema, taskIds); } } return populatedStreamConsumers; } public void newConsumer(TopologyAPI.InputStream inputStream, TopologyAPI.StreamSchema schema, List<Integer> taskIds) { consumers.add(Grouping.create(inputStream.getGtype(), inputStream, schema, taskIds)); } /** * Get all task ids from different components to send for a data tuple * * @param tuple the tuple to send * @return the target task ids to send tuple to */ public List<Integer> getListToSend(HeronTuples.HeronDataTuple tuple) { List<Integer> res = new ArrayList<>(); for (Grouping consumer : consumers) { res.addAll(consumer.getListToSend(tuple)); } return res; } // For unit test protected List<Grouping> getConsumers() { return consumers; } }