/*
* Copyright (c) 2010 Chris Smowton <chris.smowton@cl.cam.ac.uk>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package uk.co.mrry.mercator.mapreduce;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Constructor;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.RawComparator;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.mapred.RawKeyValueIterator;
import org.apache.hadoop.mapreduce.Counter;
import org.apache.hadoop.mapreduce.TaskAttemptID;
import org.apache.hadoop.mapreduce.OutputCommitter;
import org.apache.hadoop.mapreduce.RecordWriter;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.util.ReflectionUtils;
import uk.co.mrry.mercator.task.Task;
public class SWReduceEntryPoint implements Task {
@SuppressWarnings("unchecked")
@Override
public void invoke(FileInputStream[] fis, FileOutputStream[] fos, String[] args) {
// This method is used to kick off the reduce stage of a Hadoop Mapreduce job running on Skywriting
/* We assume that args supplies the necessary class names in the following form:
* 1) Mapper class name
* 2) Reducer class name
* 3) Partitioner class name
* 4) Input record reader class name (???)
* 5) Input key class
* 6) Input value class
*/
if(args.length < 4)
System.out.println("[Skywriting] Insufficient arguments passed to SWReduceEntryPoint");
String mapperClassName = args[0];
String reducerClassName = args[1];
String partitionerClassName = args[2];
String inputRecordReaderClassName = args[3];
String keyClassName = args[4];
String valueClassName = args[5];
try {
// get the key and value classes using reflection
Class keyClass = Class.forName(keyClassName);
Class valueClass = Class.forName(valueClassName);
// make a reducer
Reducer reducer = (Reducer)ReflectionUtils.newInstance(Class.forName(reducerClassName), null);
// TODO logic to run the reducer
SWReduceInputMerger merger = makeMerger(keyClass, valueClass, fis);
SWLineRecordWriter outCollector = makeLineWriter(keyClass, valueClass, fos[0]);
Reducer.Context reducerContext = null;
Constructor<Reducer.Context> contextConstructor =
Reducer.Context.class.getConstructor
(new Class[]{Reducer.class,
Configuration.class,
TaskAttemptID.class,
RawKeyValueIterator.class,
Counter.class,
Counter.class,
RecordWriter.class,
OutputCommitter.class,
RawComparator.class,
Class.class,
Class.class});
// Create a reducer context
reducerContext = contextConstructor.newInstance(reducer, null, null, null, null,
null, outCollector, null, null, null, keyClass, valueClass);
// for all keys ...
while (merger.hasMoreKeys()) {
Iterable iter = merger.getIterator();
// ... call the reduce method with the values provided by the iterator
reducer.reduce(merger.getKey(), iter, reducerContext);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private <INKEY extends WritableComparable, INVAL extends Writable>
SWReduceInputMerger makeMerger(Class<INKEY> keyClass, Class<INVAL> valClass, FileInputStream[] fis) {
return new SWReduceInputMerger<INKEY, INVAL>(fis);
}
private <OUTKEY extends WritableComparable, OUTVAL extends Writable>
SWLineRecordWriter makeLineWriter(Class<OUTKEY> keyClass, Class<OUTVAL> valClass, FileOutputStream output) {
return new SWLineRecordWriter<OUTKEY, OUTVAL>(output);
}
}