/* * Copyright 2014 DataGenerator Contributors * * 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 org.finra.datagenerator.samples.consumer; import org.apache.hadoop.mapreduce.Mapper.Context; import org.finra.datagenerator.consumer.DataConsumer; import org.finra.datagenerator.reporting.ReportingHandler; import org.finra.datagenerator.samples.manager.LineCountManager; import org.finra.datagenerator.samples.transformer.SampleMachineTransformer; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; /** * A Sample consumer which uses messaging to a host to coordinate * a global stopping condition based on total line count */ public class SampleMachineConsumer extends DataConsumer { private long lastReportedLineCount, currentLineCount; private JenkinsReportingHandler handler; private AtomicBoolean exit; private long nextReport; private long reportGap; private String[] template = new String[]{"var_out_V1", "var_out_V2", "var_out_V3", "var_out_V4", "var_out_V5", "var_out_V6", "var_out_V7", "var_out_V8", "var_out_V9"}; private long currentRow, finalRow; private class JenkinsReportingHandler implements ReportingHandler { private final AtomicBoolean exit; public JenkinsReportingHandler(final AtomicBoolean exit) { this.exit = exit; } public void handleResponse(String response) { if (response.contains("exit")) { exit.set(true); } } } private void setReportGap(long reportGap) { this.reportGap = reportGap; } /** * Constructor for SampleMachineConsumer - needs the Mapper Context * * @param context A Hadoop MapReduce Mapper.Context to which this consumer * should writer */ public SampleMachineConsumer(final Context context) { super(); ContextWriter contextWrite = new ContextWriter(context, template); this.addDataWriter(contextWrite); this.addDataTransformer(new SampleMachineTransformer()); exit = new AtomicBoolean(false); handler = new JenkinsReportingHandler(exit); currentRow = -1; finalRow = -2; setReportGap(1000); } private void makeReport(boolean force) { long time = System.currentTimeMillis(); if (time > nextReport || force) { long delta = currentLineCount - lastReportedLineCount; lastReportedLineCount = currentLineCount; sendRequest("this/report/" + String.valueOf(delta), handler); nextReport = time + reportGap; } } /** * Exit reporting up to distributor, using information gained from status reports to the LineCountManager * * @return a boolean of whether this consumer should immediately exit */ public boolean isExit() { if (currentRow > finalRow) { //request new block of work String newBlock = this.sendRequestSync("this/request/block"); LineCountManager.LineCountBlock block = new LineCountManager.LineCountBlock(0, 0); if (newBlock.contains("exit")) { getExitFlag().set(true); makeReport(true); return true; } else { block.buildFromResponse(newBlock); } currentRow = block.getStart(); finalRow = block.getStop(); } else { //report the number of lines written makeReport(false); if (exit.get()) { getExitFlag().set(true); return true; } } return false; } /** * Consume a data set (Map of Variable names and their Values) * * @param initialVars a map containing the initial variables assignments * @return Number of rows written; 0 rows if exiting 1 row otherwise */ public int consume(Map<String, String> initialVars) { if (isExit()) { return 0; } currentLineCount++; currentRow++; return super.consume(initialVars); } }