// Copyright 2017 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.instance;
import java.util.List;
import java.util.Map;
import com.google.protobuf.ByteString;
import com.twitter.heron.api.Config;
import com.twitter.heron.api.serializer.IPluggableSerializer;
import com.twitter.heron.common.basics.Communicator;
import com.twitter.heron.common.utils.metrics.ComponentMetrics;
import com.twitter.heron.common.utils.misc.PhysicalPlanHelper;
import com.twitter.heron.proto.system.HeronTuples;
/**
* Common functionality used by both bolt and spout output collectors
*/
public class AbstractOutputCollector {
protected final IPluggableSerializer serializer;
protected final OutgoingTupleCollection outputter;
protected final ComponentMetrics metrics;
protected final boolean ackEnabled;
private long totalTuplesEmitted;
private PhysicalPlanHelper helper;
public AbstractOutputCollector(IPluggableSerializer serializer,
PhysicalPlanHelper helper,
Communicator<HeronTuples.HeronTupleSet> streamOutQueue,
ComponentMetrics metrics) {
this.serializer = serializer;
this.metrics = metrics;
this.totalTuplesEmitted = 0;
updatePhysicalPlanHelper(helper);
Map<String, Object> config = helper.getTopologyContext().getTopologyConfig();
if (config.containsKey(Config.TOPOLOGY_ENABLE_ACKING)
&& config.get(Config.TOPOLOGY_ENABLE_ACKING) != null) {
this.ackEnabled = Boolean.parseBoolean(config.get(Config.TOPOLOGY_ENABLE_ACKING).toString());
} else {
this.ackEnabled = false;
}
this.outputter = new OutgoingTupleCollection(helper.getMyComponent(), streamOutQueue);
}
public void updatePhysicalPlanHelper(PhysicalPlanHelper physicalPlanHelper) {
this.helper = physicalPlanHelper;
}
public PhysicalPlanHelper getPhysicalPlanHelper() {
return helper;
}
/////////////////////////////////////////////////////////
// Following public methods are used for querying or
// interacting internal state of the output collectors
/////////////////////////////////////////////////////////
// Return true we could offer item to outQueue
public boolean isOutQueuesAvailable() {
return outputter.isOutQueuesAvailable();
}
// Return the total data emitted in bytes
public long getTotalDataEmittedInBytes() {
return outputter.getTotalDataEmittedInBytes();
}
// Flush the tuples to next stage
public void sendOutTuples() {
outputter.sendOutTuples();
}
// Clean the internal state of BoltOutputCollectorImpl
public void clear() {
outputter.clear();
}
public long getTotalTuplesEmitted() {
return totalTuplesEmitted;
}
protected HeronTuples.HeronDataTuple.Builder initTupleBuilder(String streamId,
List<Object> tuple) {
// Start construct the data tuple
HeronTuples.HeronDataTuple.Builder builder = HeronTuples.HeronDataTuple.newBuilder();
// set the key. This is mostly ignored
builder.setKey(0);
List<Integer> customGroupingTargetTaskIds = null;
if (!helper.isCustomGroupingEmpty()) {
// customGroupingTargetTaskIds will be null if this stream is not CustomStreamGrouping
customGroupingTargetTaskIds =
helper.chooseTasksForCustomStreamGrouping(streamId, tuple);
if (customGroupingTargetTaskIds != null) {
// It is a CustomStreamGrouping
builder.addAllDestTaskIds(customGroupingTargetTaskIds);
}
}
// Invoke user-defined emit task hook
helper.getTopologyContext().invokeHookEmit(tuple, streamId, customGroupingTargetTaskIds);
return builder;
}
protected void sendTuple(HeronTuples.HeronDataTuple.Builder bldr,
String streamId, List<Object> tuple) {
long tupleSizeInBytes = 0;
long startTime = System.nanoTime();
// Serialize it
for (Object obj : tuple) {
byte[] b = serializer.serialize(obj);
ByteString bstr = ByteString.copyFrom(b);
bldr.addValues(bstr);
tupleSizeInBytes += b.length;
}
long latency = System.nanoTime() - startTime;
metrics.serializeDataTuple(streamId, latency);
// submit to outputter
outputter.addDataTuple(streamId, bldr, tupleSizeInBytes);
totalTuplesEmitted++;
// Update metrics
metrics.emittedTuple(streamId);
}
}