I have a patch that tries to use file links instead of making a copy of the
data that is already available locally. I tested it on the a single machine
cluster configuration running 48 mappers and reducers. I unfortunately do
not have access to a cluster even a small one. Can some on review and test
run my patch ?
I created the patch using Eclipse against 1.0.3. My knowledge in Java in
limited and the code is not well written in some classes. So please let me
know if I need to make changes to the code along with a short explanation
of the change. I will happily do so.
Thanks,
Suresh.
### Eclipse Workspace Patch 1.0
#P hadoop-1.0.4
Index: src/mapred/org/apache/hadoop/mapred/TaskCompletionEvent.java
===================================================================
--- src/mapred/org/apache/hadoop/mapred/TaskCompletionEvent.java
(revision 1401127)
+++ src/mapred/org/apache/hadoop/mapred/TaskCompletionEvent.java
(working copy)
@@ -30,6 +30,11 @@
* job tracker.
*/
public class TaskCompletionEvent implements Writable{
+
+ public String getTaskTrackerName() {
+ return taskTrackerName;
+ }
+
static public enum Status {FAILED, KILLED, SUCCEEDED, OBSOLETE, TIPFAILED};
private int eventId;
@@ -39,6 +44,12 @@
Status status;
boolean isMap = false;
private int idWithinJob;
+ private boolean isMapOutputLocal = false;
+ private String mapOutputLocation = null;
+ private long mapOutputOffSet = 0;
+ private long mapOutputReadLength = 0;
+ private long mapOutputRawLength = 0;
+ private String taskTrackerName = null;
public static final TaskCompletionEvent[] EMPTY_ARRAY =
new TaskCompletionEvent[0];
/**
@@ -63,7 +74,7 @@
int idWithinJob,
boolean isMap,
Status status,
- String taskTrackerHttp){
+ String taskTrackerHttp, String taskTrackerName){
this.taskId = taskId;
this.idWithinJob = idWithinJob;
@@ -71,7 +82,57 @@
this.eventId = eventId;
this.status =status;
this.taskTrackerHttp = taskTrackerHttp;
+ this.taskTrackerName = taskTrackerName;
+ }
+
+ public TaskCompletionEvent(int eventId,
+ TaskAttemptID taskId,
+ int idWithinJob,
+ boolean isMap,
+ Status status,
+ String taskTrackerHttp,
+ boolean sameTaskTrackerForMap, String mapOutputLocation, long
mapOutputOffSet, long mapOutputReadLength, long mapOutputUnCompressedLength,
String taskTrackerName){
+
+ this.taskId = taskId;
+ this.idWithinJob = idWithinJob;
+ this.isMap = isMap;
+ this.eventId = eventId;
+ this.status =status;
+ this.taskTrackerHttp = taskTrackerHttp;
+ this.isMapOutputLocal = sameTaskTrackerForMap;
+ this.mapOutputLocation = mapOutputLocation;
+ this.mapOutputOffSet = mapOutputOffSet;
+ this.mapOutputReadLength = mapOutputReadLength;
+ this.taskTrackerName = taskTrackerName;
+ this.mapOutputRawLength = mapOutputUnCompressedLength;
+ }
+
+ /**
+ * Returns true or false depending of if the map event occured on the same
task tracker as the reducer requesting the event
+ * @return boolean
+ */
+ public boolean isSameTaskTrackerForMap() {
+ return isMapOutputLocal;
+ }
+
+ public String getMapOutputLocation() {
+ return mapOutputLocation;
+ }
+
+ public long getMapOutputOffSet()
+ {
+ return mapOutputOffSet;
+ }
+
+ public long getMapOutputReadLength()
+ {
+ return mapOutputReadLength;
+ }
+
+ public long getMapOutputRawLength() {
+ return mapOutputRawLength;
}
+
/**
* Returns event Id.
* @return event id
@@ -128,6 +189,32 @@
}
/**
+ * Set true or false depending of if the map event occured on the same task
tracker as the reducer requesting the event
+ * @param sameTaskTrackerForMap boolean
+ */
+ public void setMapOutputLocal(boolean isMapOutputLocal) {
+ this.isMapOutputLocal = isMapOutputLocal;
+ }
+
+ public void setMapOutputLocation(String mapOutputLocation) {
+ this.mapOutputLocation = mapOutputLocation;
+ }
+
+ public void setMapOutputOffSet(long mapOutputOffSet)
+ {
+ this.mapOutputOffSet = mapOutputOffSet;
+ }
+
+ public void setMapOutputReadLength(long mapOutputReadLength)
+ {
+ this.mapOutputReadLength = mapOutputReadLength;
+ }
+
+ public void setMapOutputRawLength(long mapOutputUnCompressedLength) {
+ this.mapOutputRawLength = mapOutputUnCompressedLength;
+ }
+
+ /**
* set event Id. should be assigned incrementally starting from 0.
* @param eventId
*/
@@ -192,7 +279,12 @@
&& this.status.equals(event.getTaskStatus())
&& this.taskId.equals(event.getTaskAttemptId())
&& this.taskRunTime == event.getTaskRunTime()
- && this.taskTrackerHttp.equals(event.getTaskTrackerHttp());
+ && this.taskTrackerHttp.equals(event.getTaskTrackerHttp())
+ && this.isMapOutputLocal == event.isMapOutputLocal
+ && this.mapOutputLocation.equals(event.mapOutputLocation)
+ && this.mapOutputOffSet == event.mapOutputOffSet
+ && this.mapOutputReadLength == event.mapOutputReadLength
+ && this.mapOutputRawLength == event.mapOutputRawLength;
}
return false;
}
@@ -220,6 +312,12 @@
WritableUtils.writeString(out, taskTrackerHttp);
WritableUtils.writeVInt(out, taskRunTime);
WritableUtils.writeVInt(out, eventId);
+ out.writeBoolean(isMapOutputLocal);
+ WritableUtils.writeString(out, mapOutputLocation);
+ WritableUtils.writeVLong(out, mapOutputOffSet);
+ WritableUtils.writeVLong(out, mapOutputReadLength);
+ WritableUtils.writeVLong(out,mapOutputRawLength);
+ WritableUtils.writeString(out, taskTrackerName);
}
public void readFields(DataInput in) throws IOException {
@@ -230,5 +328,11 @@
taskTrackerHttp = WritableUtils.readString(in);
taskRunTime = WritableUtils.readVInt(in);
eventId = WritableUtils.readVInt(in);
+ isMapOutputLocal = in.readBoolean();
+ mapOutputLocation = WritableUtils.readString(in);
+ mapOutputOffSet = WritableUtils.readVLong(in);
+ mapOutputReadLength = WritableUtils.readVLong(in);
+ mapOutputRawLength = WritableUtils.readVLong(in);
+ taskTrackerName = WritableUtils.readString(in);
}
}
Index: src/mapred/org/apache/hadoop/mapred/JobInProgress.java
===================================================================
--- src/mapred/org/apache/hadoop/mapred/JobInProgress.java (revision
1401127)
+++ src/mapred/org/apache/hadoop/mapred/JobInProgress.java (working copy)
@@ -1121,7 +1121,8 @@
!tip.isJobCleanupTask() &&
!tip.isJobSetupTask(),
TaskCompletionEvent.Status.SUCCEEDED,
- httpTaskLogLocation
+ httpTaskLogLocation ,
+ taskTracker.getTrackerName()
);
taskEvent.setTaskRunTime((int)(status.getFinishTime()
- status.getStartTime()));
@@ -1177,7 +1178,8 @@
!tip.isJobCleanupTask() &&
!tip.isJobSetupTask(),
taskCompletionStatus,
- httpTaskLogLocation
+ httpTaskLogLocation,
+ taskTracker.getTrackerName()
);
}
Index: src/mapred/org/apache/hadoop/mapred/ReduceTask.java
===================================================================
--- src/mapred/org/apache/hadoop/mapred/ReduceTask.java (revision 1401127)
+++ src/mapred/org/apache/hadoop/mapred/ReduceTask.java (working copy)
@@ -21,6 +21,7 @@
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -55,6 +56,7 @@
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileSystem.Statistics;
+import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.LocalFileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.DataInputBuffer;
@@ -140,7 +142,7 @@
return -1;
else if (a.getLen() == b.getLen())
if (a.getPath().toString().equals(b.getPath().toString()))
- return 0;
+ return (a.getOffset() == b.getOffset() ? 0 : (a.getOffset() <
b.getOffset()) ? 1 : -1);
else
return -1;
else
@@ -361,7 +363,6 @@
reporter.startCommunicationThread();
boolean useNewApi = job.getUseNewReducer();
initialize(job, getJobID(), reporter, useNewApi);
-
// check if it is a cleanupJobTask
if (jobCleanup) {
runJobCleanupTask(umbilical, reporter);
@@ -378,9 +379,11 @@
// Initialize the codec
codec = initCodec();
-
- boolean isLocal = "local".equals(job.get("mapred.job.tracker", "local"));
+
+ String trackerloc = job.get("mapred.job.tracker", "local");
+ boolean isLocal = "local".equals(trackerloc);
if (!isLocal) {
+ LOG.info(" The task is not a single threaded map-reduce job ");
reduceCopier = new ReduceCopier(umbilical, job, reporter);
if (!reduceCopier.fetchOutputs()) {
if(reduceCopier.mergeThrowable instanceof FSError) {
@@ -391,6 +394,7 @@
}
}
copyPhase.complete(); // copy is already complete
+ LOG.info("Copy phase is complete");
setPhase(TaskStatus.Phase.SORT);
statusUpdate(umbilical);
@@ -407,6 +411,7 @@
mapOutputFilesOnDisk.clear();
sortPhase.complete(); // sort is complete
+ LOG.info("Sort phase is complete");
setPhase(TaskStatus.Phase.REDUCE);
statusUpdate(umbilical);
Class keyClass = job.getMapOutputKeyClass();
@@ -998,10 +1003,14 @@
* Abstraction to track a map-output.
*/
private class MapOutputLocation {
+
TaskAttemptID taskAttemptId;
TaskID taskId;
String ttHost;
URL taskOutput;
+ long offSet;
+ long length;
+ long rawLength;
public MapOutputLocation(TaskAttemptID taskAttemptId,
String ttHost, URL taskOutput) {
@@ -1009,6 +1018,19 @@
this.taskId = this.taskAttemptId.getTaskID();
this.ttHost = ttHost;
this.taskOutput = taskOutput;
+ this.offSet = 0;
+ this.length = 0;
+ }
+
+ public MapOutputLocation(TaskAttemptID taskAttemptId,
+ String ttHost, URL taskOutput, long offSet, long length, long
rawLength) {
+ this.taskAttemptId = taskAttemptId;
+ this.taskId = this.taskAttemptId.getTaskID();
+ this.ttHost = ttHost;
+ this.taskOutput = taskOutput;
+ this.offSet = offSet;
+ this.length = length;
+ this.rawLength = rawLength;
}
public TaskAttemptID getTaskAttemptId() {
@@ -1026,6 +1048,18 @@
public URL getOutputLocation() {
return taskOutput;
}
+
+ public long getOffSet() {
+ return offSet;
+ }
+
+ public long getLength() {
+ return length;
+ }
+
+ public long getRawLength() {
+ return rawLength;
+ }
}
/** Describes the output of a map; could either be on disk or in-memory. */
@@ -1039,7 +1073,7 @@
byte[] data;
final boolean inMemory;
long compressedSize;
-
+ long offSet ;
public MapOutput(TaskID mapId, TaskAttemptID mapAttemptId,
Configuration conf, Path file, long size) {
this.mapId = mapId;
@@ -1047,6 +1081,7 @@
this.conf = conf;
this.file = file;
+ this.offSet = 0;
this.compressedSize = size;
this.data = null;
@@ -1054,6 +1089,21 @@
this.inMemory = false;
}
+ public MapOutput(TaskID mapId, TaskAttemptID mapAttemptId,
+ Configuration conf, Path file, long offSet, long length) {
+ this.mapId = mapId;
+ this.mapAttemptId = mapAttemptId;
+
+ this.conf = conf;
+ this.file = file;
+ this.offSet = offSet;
+ this.compressedSize = length;
+
+ this.data = null;
+
+ this.inMemory = false;
+ }
+
public MapOutput(TaskID mapId, TaskAttemptID mapAttemptId, byte[] data,
int compressedLength) {
this.mapId = mapId;
this.mapAttemptId = mapAttemptId;
@@ -1401,7 +1451,6 @@
// The size of the map-output
long bytes = mapOutput.compressedSize;
-
// lock the ReduceTask while we do the rename
synchronized (ReduceTask.this) {
if (copiedMapOutputs.contains(loc.getTaskId())) {
@@ -1411,12 +1460,12 @@
// Special case: discard empty map-outputs
if (bytes == 0) {
+ LOG.info("Discarding file as the size is zero " + mapOutput.file);
try {
mapOutput.discard();
} catch (IOException ioe) {
LOG.info("Couldn't discard output of " + loc.getTaskId());
}
-
// Note that we successfully copied the map-output
noteCopiedMapOutput(loc.getTaskId());
@@ -1439,8 +1488,11 @@
tmpMapOutput + " to " + filename);
}
- synchronized (mapOutputFilesOnDisk) {
- addToMapOutputFilesOnDisk(localFileSys.getFileStatus(filename));
+ synchronized (mapOutputFilesOnDisk) {
+ FileStatus fstatus = localFileSys.getFileStatus(filename);
+ fstatus.setLength(mapOutput.compressedSize);
+ fstatus.setOffset(mapOutput.offSet);
+ addToMapOutputFilesOnDisk(fstatus);
}
}
@@ -1476,12 +1528,47 @@
private MapOutput getMapOutput(MapOutputLocation mapOutputLoc,
Path filename, int reduce)
throws IOException, InterruptedException {
+
// Connect
URL url = mapOutputLoc.getOutputLocation();
URLConnection connection = url.openConnection();
- InputStream input = setupSecureConnection(mapOutputLoc, connection);
-
+ String tasktracker = url.getHost();
+ InputStream input = null;
+ MapOutput mapOutput = null;
+ if(tasktracker == null)
+ {
+ try{
+ if( ramManager.canFitInMemory(mapOutputLoc.getRawLength()) )
+ {
+ LOG.info("Task tracker is null , so doing shuffle to disk as
link but in memory");
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Shuffling local map output " +
mapOutputLoc.getRawLength() + " bytes (" +
+ mapOutputLoc.getLength() + " raw bytes) " +
+ "into RAM from " + mapOutputLoc.getTaskAttemptId());
+ }
+ FileInputStream fis = new FileInputStream(new
File(mapOutputLoc.getOutputLocation().getPath()));
+ fis.getChannel().position(mapOutputLoc.getOffSet());
+ input = fis;
+ mapOutput = shuffleInMemory(mapOutputLoc, null, input,
+ (int)mapOutputLoc.getRawLength(),
+ (int)mapOutputLoc.getLength());
+ }
+ else
+ {
+ LOG.info("Task tracker is null , so doing shuffle to disk as
link");
+ mapOutput = shuffleToDiskAsLink(mapOutputLoc, filename);
+ }
+ return mapOutput;
+ } catch(IOException ioe)
+ {
+ LOG.error("Shuffle as Link did not work \n " + ioe.getMessage());
+ }
+ }
+ LOG.info("Task tracker is not null , so doing shuffle to disk usual
way");
+
+ input = setupSecureConnection(mapOutputLoc, connection);
+
// Validate header from map output
TaskAttemptID mapId = null;
try {
@@ -1534,14 +1621,12 @@
boolean shuffleInMemory =
ramManager.canFitInMemory(decompressedLength);
// Shuffle
- MapOutput mapOutput = null;
if (shuffleInMemory) {
if (LOG.isDebugEnabled()) {
LOG.debug("Shuffling " + decompressedLength + " bytes (" +
compressedLength + " raw bytes) " +
"into RAM from " + mapOutputLoc.getTaskAttemptId());
}
-
mapOutput = shuffleInMemory(mapOutputLoc, connection, input,
(int)decompressedLength,
(int)compressedLength);
@@ -1656,8 +1741,18 @@
if (!createdNow) {
// Reconnect
try {
- connection = mapOutputLoc.getOutputLocation().openConnection();
- input = setupSecureConnection(mapOutputLoc, connection);
+ URL url = mapOutputLoc.getOutputLocation();
+ if( connection == null)
+ {
+ FileInputStream fis = new FileInputStream(new
File(url.getPath()));
+ fis.getChannel().position(mapOutputLoc.getOffSet());
+ input = fis;
+ }
+ else
+ {
+ connection = url.openConnection();
+ input = setupSecureConnection(mapOutputLoc, connection);
+ }
} catch (IOException ioe) {
LOG.info("Failed reopen connection to fetch map-output from " +
mapOutputLoc.getHost());
@@ -1772,6 +1867,21 @@
return mapOutput;
}
+ private MapOutput shuffleToDiskAsLink(MapOutputLocation mapOutputLoc,
Path filename) throws IOException
+ {
+ // Find out a suitable location for the output on local-filesystem
+ Path localFilename =
+ lDirAlloc.getLocalPathForWrite(filename.toUri().getPath(),
+ mapOutputLoc.getLength(), conf);
+
+ MapOutput mapOutput =
+ new MapOutput(mapOutputLoc.getTaskId(),
mapOutputLoc.getTaskAttemptId(),
+ conf, localFileSys.makeQualified(localFilename),
+ mapOutputLoc.getOffSet(), mapOutputLoc.getLength());
+ FileUtil.symLink(mapOutputLoc.getOutputLocation().getPath(),
localFilename.toUri().getPath());
+ return mapOutput;
+ }
+
private MapOutput shuffleToDisk(MapOutputLocation mapOutputLoc,
InputStream input,
Path filename,
@@ -2352,6 +2462,7 @@
return false;
}
}
+ LOG.info("Completed FetchOutputs");
return mergeThrowable == null && copiedMapOutputs.size() == numMaps;
}
@@ -2433,6 +2544,7 @@
List<Segment<K,V>> memDiskSegments = new ArrayList<Segment<K,V>>();
long inMemToDiskBytes = 0;
if (mapOutputsFilesInMemory.size() > 0) {
+ LOG.info("In-memory files to be merged");
TaskID mapId = mapOutputsFilesInMemory.get(0).mapId;
inMemToDiskBytes = createInMemorySegments(memDiskSegments,
maxInMemReduce);
@@ -2449,16 +2561,15 @@
keyClass, valueClass, codec, null);
try {
Merger.writeFile(rIter, writer, reporter, job);
+ if (null != writer) {
+ writer.close();
+ }
addToMapOutputFilesOnDisk(fs.getFileStatus(outputPath));
} catch (Exception e) {
if (null != outputPath) {
fs.delete(outputPath, true);
}
throw new IOException("Final merge failed", e);
- } finally {
- if (null != writer) {
- writer.close();
- }
}
LOG.info("Merged " + numMemDiskSegments + " segments, " +
inMemToDiskBytes + " bytes to disk to satisfy " +
@@ -2472,15 +2583,15 @@
}
}
+ LOG.info("Completed in-memory merge and now moving to file merge");
// segments on disk
List<Segment<K,V>> diskSegments = new ArrayList<Segment<K,V>>();
long onDiskBytes = inMemToDiskBytes;
- Path[] onDisk = getMapFiles(fs, false);
- for (Path file : onDisk) {
- onDiskBytes += fs.getFileStatus(file).getLen();
- diskSegments.add(new Segment<K, V>(job, fs, file, codec, keepInputs));
+ for (FileStatus filestatus : mapOutputFilesOnDisk) {
+ onDiskBytes += filestatus.getLen();
+ diskSegments.add(new Segment<K, V>(job, fs, filestatus.getPath(),
filestatus.getOffset(), filestatus.getLen(), codec, keepInputs));
}
- LOG.info("Merging " + onDisk.length + " files, " +
+ LOG.info("Merging " + mapOutputFilesOnDisk.size() + " files, " +
onDiskBytes + " bytes from disk");
Collections.sort(diskSegments, new Comparator<Segment<K,V>>() {
public int compare(Segment<K, V> o1, Segment<K, V> o2) {
@@ -2604,9 +2715,10 @@
}
}
if(exitLocalFSMerge) {//to avoid running one extra time in the end
+ LOG.info("Exiting Local FS Merge");
break;
}
- List<Path> mapFiles = new ArrayList<Path>();
+ List<FileStatus> mapFiles = new ArrayList<FileStatus>();
long approxOutputSize = 0;
int bytesPerSum =
reduceTask.getConf().getInt("io.bytes.per.checksum", 512);
@@ -2620,16 +2732,19 @@
for (int i = 0; i < ioSortFactor; ++i) {
FileStatus filestatus = mapOutputFilesOnDisk.first();
mapOutputFilesOnDisk.remove(filestatus);
- mapFiles.add(filestatus.getPath());
+ mapFiles.add(filestatus);
approxOutputSize += filestatus.getLen();
+ LOG.info("File name:" + filestatus.getPath() +
+ " File Offset: " + filestatus.getOffset() +
+ " File Length: " + filestatus.getLength());
}
}
// sanity check
if (mapFiles.size() == 0) {
+ LOG.info("No map files to work with for FS Merger");
return;
}
-
// add the checksum length
approxOutputSize += ChecksumFileSystem
.getChecksumLength(approxOutputSize,
@@ -2651,11 +2766,11 @@
iter = Merger.merge(conf, rfs,
conf.getMapOutputKeyClass(),
conf.getMapOutputValueClass(),
- codec, mapFiles.toArray(new
Path[mapFiles.size()]),
+ codec, mapFiles.toArray(new
FileStatus[mapFiles.size()]),
true, ioSortFactor, tmpDir,
conf.getOutputKeyComparator(), reporter,
spilledRecordsCounter, null);
-
+
Merger.writeFile(iter, writer, reporter, conf);
writer.close();
} catch (Exception e) {
@@ -2842,14 +2957,15 @@
private int getMapCompletionEvents() throws IOException {
int numNewMaps = 0;
-
+ LOG.debug(" Received request for completionevents fromEventId " +
fromEventId.get() +
+ " Taskattemptid " + reduceTask.getTaskID() + " maxlocs " +
MAX_EVENTS_TO_FETCH );
MapTaskCompletionEventsUpdate update =
umbilical.getMapCompletionEvents(reduceTask.getJobID(),
fromEventId.get(),
MAX_EVENTS_TO_FETCH,
reduceTask.getTaskID(), jvmContext);
TaskCompletionEvent events[] = update.getMapTaskCompletionEvents();
-
+
// Check if the reset is required.
// Since there is no ordering of the task completion events at the
// reducer, the only option to sync with the new jobtracker is to
reset
@@ -2873,20 +2989,39 @@
switch (event.getTaskStatus()) {
case SUCCEEDED:
{
- URI u = URI.create(event.getTaskTrackerHttp());
- String host = u.getHost();
- TaskAttemptID taskId = event.getTaskAttemptId();
- URL mapOutputLocation = new URL(event.getTaskTrackerHttp() +
- "/mapOutput?job=" + taskId.getJobID() +
- "&map=" + taskId +
- "&reduce=" + getPartition());
+ URL mapOutputLocation = null;
+ String host = null;
+ TaskAttemptID taskId = null;
+ if(event.isSameTaskTrackerForMap()){
+
+ mapOutputLocation = new URL("file", null,
event.getMapOutputLocation());
+ host = "Local-FS";
+ taskId = event.getTaskAttemptId();
+ LOG.info("Map and Reducer are on the same machine: " +
+ " Offset " + event.getMapOutputOffSet() +
+ " Length " + event.getMapOutputReadLength() +
+ " Trackername " + event.getTaskTrackerName());
+
+ } else {
+ URI u = URI.create(event.getTaskTrackerHttp());
+ host = u.getHost();
+ taskId = event.getTaskAttemptId();
+ mapOutputLocation = new URL(event.getTaskTrackerHttp() +
+ "/mapOutput?job=" + taskId.getJobID() +
+ "&map=" + taskId +
+ "&reduce=" + getPartition());
+ LOG.info("Map and Reducer are not on the same machine: " +
+ " Offset " + event.getMapOutputOffSet() +
+ " Length " + event.getMapOutputReadLength() +
+ " Trackername " + event.getTaskTrackerName());
+ }
List<MapOutputLocation> loc = mapLocations.get(host);
if (loc == null) {
loc = Collections.synchronizedList
(new LinkedList<MapOutputLocation>());
mapLocations.put(host, loc);
}
- loc.add(new MapOutputLocation(taskId, host, mapOutputLocation));
+ loc.add(new MapOutputLocation(taskId, host,
mapOutputLocation,event.getMapOutputOffSet(),event.getMapOutputReadLength(),
event.getMapOutputRawLength()));
numNewMaps ++;
}
break;
Index: src/core/org/apache/hadoop/fs/FileStatus.java
===================================================================
--- src/core/org/apache/hadoop/fs/FileStatus.java (revision 1401127)
+++ src/core/org/apache/hadoop/fs/FileStatus.java (working copy)
@@ -39,10 +39,18 @@
private FsPermission permission;
private String owner;
private String group;
+ private long offset;
public FileStatus() { this(0, false, 0, 0, 0, 0, null, null, null, null); }
//We should deprecate this soon?
+ public FileStatus(long offset, long length, boolean isdir, int
block_replication,
+ long blocksize, long modification_time, Path path) {
+ this(length, isdir, block_replication, blocksize, modification_time,
+ 0, null, null, null, path);
+ this.offset = offset;
+ }
+
public FileStatus(long length, boolean isdir, int block_replication,
long blocksize, long modification_time, Path path) {
@@ -65,8 +73,25 @@
this.owner = (owner == null) ? "" : owner;
this.group = (group == null) ? "" : group;
this.path = path;
+ this.offset = 0;
}
+ public long getOffset() {
+ return offset;
+ }
+
+ public void setOffset(long offset) {
+ this.offset = offset;
+ }
+
+ public long getLength() {
+ return length;
+ }
+
+ public void setLength(long length) {
+ this.length = length;
+ }
+
/*
* @return the length of this file, in blocks
*/
@@ -191,6 +216,7 @@
permission.write(out);
Text.writeString(out, owner);
Text.writeString(out, group);
+ out.writeLong(offset);
}
public void readFields(DataInput in) throws IOException {
@@ -205,6 +231,7 @@
permission.readFields(in);
owner = Text.readString(in);
group = Text.readString(in);
+ offset = in.readLong();
}
/**
Index: src/mapred/org/apache/hadoop/mapred/TaskTracker.java
===================================================================
--- src/mapred/org/apache/hadoop/mapred/TaskTracker.java (revision
1401127)
+++ src/mapred/org/apache/hadoop/mapred/TaskTracker.java (working copy)
@@ -3525,10 +3525,15 @@
LOG.warn("Unknown child task fatalError: "+taskId+". Ignored.");
}
}
-
+
+ private static LRUCache<String, Path> fileCache = new LRUCache<String,
Path>(FILE_CACHE_SIZE);
+ private static LRUCache<String, Path> fileIndexCache = new LRUCache<String,
Path>(FILE_CACHE_SIZE);
+
public synchronized MapTaskCompletionEventsUpdate getMapCompletionEvents(
JobID jobId, int fromEventId, int maxLocs, TaskAttemptID id,
JvmContext jvmContext) throws IOException {
+ LOG.info(" Received request for completionevents fromEventId " +
fromEventId +
+ " Taskattemptid " + id + " maxlocs " + maxLocs );
TaskInProgress tip = runningTasks.get(id);
if (tip == null) {
throw new IOException("Unknown task; " + id
@@ -3542,7 +3547,10 @@
return new MapTaskCompletionEventsUpdate(mapEvents, true);
}
}
+
RunningJob rjob;
+ String userName = null;
+
synchronized (runningJobs) {
rjob = runningJobs.get(jobId);
if (rjob != null) {
@@ -3550,9 +3558,60 @@
FetchStatus f = rjob.getFetchStatus();
if (f != null) {
mapEvents = f.getMapEvents(fromEventId, maxLocs);
+ userName = rjob.jobConf.getUser();
+ }
+ }
+ }
+ }
+ for(TaskCompletionEvent event : mapEvents)
+ {
+ if( event.getTaskTrackerName().equals(this.taskTrackerName ) &&
event.getTaskStatus() == TaskCompletionEvent.Status.SUCCEEDED )
+ {
+ // Optimize
+ try{
+ event.setMapOutputLocal(true);
+ LOG.info(" Job id method " + jobId.toString() + " Job id event" +
event.getTaskAttemptId().getJobID().toString());
+ String intermediateOutputDir = getIntermediateOutputDir(userName,
event.getTaskAttemptId().getJobID().toString(),
event.getTaskAttemptId().toString());
+ // Index file
+ String indexKey = intermediateOutputDir + "/file.out.index";
+ Path indexFileName = fileIndexCache.get(indexKey);
+ if (indexFileName == null) {
+ indexFileName = lDirAlloc.getLocalPathToRead(indexKey, fConf);
+ fileIndexCache.put(indexKey, indexFileName);
+ }
+
+ // Map-output file
+ String fileKey = intermediateOutputDir + "/file.out";
+ Path mapOutputFileName = fileCache.get(fileKey);
+ if (mapOutputFileName == null) {
+ mapOutputFileName = lDirAlloc.getLocalPathToRead(fileKey, fConf);
+ fileCache.put(fileKey, mapOutputFileName);
}
+
+
+ String runAsUserName =
getTaskController().getRunAsUser(rjob.jobConf);
+ IndexRecord info =
+
indexCache.getIndexInformation(event.getTaskAttemptId().toString(),
tip.task.getPartition() ,indexFileName,
+ runAsUserName);
+
+ event.setMapOutputLocation(mapOutputFileName.toUri().getPath());
+ event.setMapOutputOffSet(info.startOffset);
+ event.setMapOutputReadLength(info.partLength);
+ event.setMapOutputRawLength(info.rawLength);
+ LOG.info(" Event info " + mapOutputFileName.toUri().getPath() +
+ " Offset " + info.startOffset +
+ " Length " + info.partLength +
+ " paritition " + tip.task.getPartition() +
+ " task attempt id " +
event.getTaskAttemptId().toString());
+ }
+ catch(Exception e)
+ {
+ // Continue as if nothing happened.
+ event.setMapOutputLocal(false);
}
}
+ else
+ LOG.info("TaskTracker local is " + this.taskTrackerName + " and the
event occured in " + event.getTaskTrackerName());
}
return new MapTaskCompletionEventsUpdate(mapEvents, false);
}
Index: src/mapred/org/apache/hadoop/mapred/Merger.java
===================================================================
--- src/mapred/org/apache/hadoop/mapred/Merger.java (revision 1401127)
+++ src/mapred/org/apache/hadoop/mapred/Merger.java (working copy)
@@ -28,6 +28,7 @@
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.ChecksumFileSystem;
+import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.LocalDirAllocator;
import org.apache.hadoop.fs.Path;
@@ -66,6 +67,29 @@
public static <K extends Object, V extends Object>
RawKeyValueIterator merge(Configuration conf, FileSystem fs,
+ Class<K> keyClass, Class<V> valueClass,
+ CompressionCodec codec,
+ FileStatus[] inputs, boolean deleteInputs,
+ int mergeFactor, Path tmpDir,
+ RawComparator<K> comparator, Progressable reporter,
+ Counters.Counter readsCounter,
+ Counters.Counter writesCounter)
+ throws IOException {
+ // segments on disk
+ List<Segment<K,V>> diskSegments = new ArrayList<Segment<K,V>>();
+ for (FileStatus filestatus : inputs) {
+ diskSegments.add(new Segment<K, V>(conf, fs, filestatus.getPath(),
filestatus.getOffset(), filestatus.getLen(), codec, !deleteInputs));
+ }
+
+ return new MergeQueue<K, V>(conf, fs, diskSegments, comparator, reporter,
+ true).merge(keyClass, valueClass,
+ mergeFactor,
+ tmpDir,
+ readsCounter, writesCounter);
+ }
+
+ public static <K extends Object, V extends Object>
+ RawKeyValueIterator merge(Configuration conf, FileSystem fs,
Class<K> keyClass, Class<V> valueClass,
CompressionCodec codec,
List<Segment<K, V>> segments,
@@ -179,7 +203,7 @@
CompressionCodec codec, boolean preserve) throws
IOException {
this(conf, fs, file, 0, fs.getFileStatus(file).getLen(), codec,
preserve);
}
-
+
public Segment(Configuration conf, FileSystem fs, Path file,
long segmentOffset, long segmentLength, CompressionCodec codec,
boolean preserve) throws IOException {
@@ -192,7 +216,7 @@
this.segmentOffset = segmentOffset;
this.segmentLength = segmentLength;
}
-
+
public Segment(Reader<K, V> reader, boolean preserve) {
this.reader = reader;
this.preserve = preserve;
@@ -204,7 +228,7 @@
if (reader == null) {
FSDataInputStream in = fs.open(file);
in.seek(segmentOffset);
- reader = new Reader<K, V>(conf, in, segmentLength, codec,
readsCounter);
+ reader = new Reader<K, V>(conf, in, segmentLength, codec,
readsCounter);
}
}