package nl.us2.cloudpelican.stormprocessor;
/**
* Created by robin on 07/06/15.
*/
import backtype.storm.Config;
import backtype.storm.task.OutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseRichBolt;
import backtype.storm.tuple.Tuple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import storm.starter.util.TupleHelpers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
*
* @author robin
*/
public class SupervisorResultWriterBolt extends BaseRichBolt {
OutputCollector _collector;
HashMap<String, ArrayList<String>> resultAggregator;
public Settings settings;
private static final int BATCH_SIZE = 2000;
private Executor executor;
private static final Logger LOG = LoggerFactory.getLogger(SupervisorResultWriterBolt.class);
public SupervisorResultWriterBolt(Settings settings) {
super();
this.settings = settings;
}
public void prepare(Map conf, TopologyContext context, OutputCollector collector) {
_collector = collector;
resultAggregator = new HashMap<String, ArrayList<String>>();
executor = Executors.newFixedThreadPool(2);
}
public void execute(Tuple tuple) {
if (TupleHelpers.isTickTuple(tuple)) {
_collector.ack(tuple);
executeTick();
} else {
executeTuple(tuple);
_collector.ack(tuple);
}
}
public void executeTick() {
_flush();
}
protected void _flush() {
for (Map.Entry<String, ArrayList<String>> kv : resultAggregator.entrySet()) {
_flushFilter(kv.getKey(), kv.getValue());
}
resultAggregator.clear();
}
protected void _flushFilter(String filterId, ArrayList<String> data) {
try {
// To string
StringBuilder sb = new StringBuilder();
for (String line : data) {
sb.append(line).append("\n");
}
// Execute async
String url = settings.get("supervisor_host") + "filter/" + filterId + "/result";
executor.execute(new SupervisorResultWriterRunnable(this, url, sb.toString()));
// Clear
data.clear();
} catch (Exception e) {
LOG.error("Failed to write data to supervisor", e);
}
}
public Map<String, Object> getComponentConfiguration() {
Config conf = new Config();
int tickFrequencyInSeconds = 1;
conf.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS, tickFrequencyInSeconds);
return conf;
}
public void executeTuple(Tuple tuple) {
String filterId = tuple.getStringByField("filter_id");
String msg = tuple.getStringByField("msg");
long ts = tuple.getLongByField("ts");
// Append in-memory
if (!resultAggregator.containsKey(filterId)) {
resultAggregator.put(filterId, new ArrayList<String>());
}
resultAggregator.get(filterId).add(msg);
// Flush if we have a lot of messages in memory
if (resultAggregator.get(filterId).size() > BATCH_SIZE) {
_flushFilter(filterId, resultAggregator.get(filterId));
}
// No ack, is handled in outer
}
public void declareOutputFields(OutputFieldsDeclarer declarer) {
}
}