- ①获取当前输入目录中所有的文件
- ②以文件为单位切片,如果文件为空文件,默认创建一个空的切片
- ③如果文件不为空,尝试判断文件是否可切(不是压缩文件,都可切)
- ④如果文件不可切,整个文件作为1片
- ⑤如果文件可切,先获取片大小(默认等于块大小),循环判断
待切部分/ 片大小 > 1.1
,如果大于先切去一片,再判断… - ⑥剩余部分整个作为1片
以下为源码部分
public List getSplits(JobContext job) throws IOException {
StopWatch sw = new StopWatch().start();
// minSize从mapreduce.input.fileinputformat.split.minsize和1之间对比,取最大值
long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));
// 读取mapreduce.input.fileinputformat.split.maxsize,如果没有设置使用Long.MaxValue作为默认值
long maxSize = getMaxSplitSize(job);
// generate splits
List splits = new ArrayList();
// 获取当前Job输入目录中所有文件的状态(元数据)
List files = listStatus(job);
// 以文件为单位进行切片
for (FileStatus file: files) {
Path path = file.getPath();
long length = file.getLen();
if (length != 0) {
BlockLocation[] blkLocations;
if (file instanceof LocatedFileStatus) {
blkLocations = ((LocatedFileStatus) file).getBlockLocations();
} else {
FileSystem fs = path.getFileSystem(job.getConfiguration());
blkLocations = fs.getFileBlockLocations(file, 0, length);
}
// 判断当前文件是否可切,如果可切,切片
if (isSplitable(job, path)) {
long blockSize = file.getBlockSize();
long splitSize = computeSplitSize(blockSize, minSize, maxSize);
// 声明待切部分数据的余量
long bytesRemaining = length;
// 如果 待切部分 / 片大小 > 1.1,先切去一片,再判断
while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {
int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);
splits.add(makeSplit(path, length-bytesRemaining, splitSize,
blkLocations[blkIndex].getHosts(),
blkLocations[blkIndex].getCachedHosts()));
bytesRemaining -= splitSize;
}
// 否则,将剩余部分整个作为1片。 最后一片有可能超过片大小,但是不超过其1.1倍
if (bytesRemaining != 0) {
int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);
splits.add(makeSplit(path, length-bytesRemaining, bytesRemaining,
blkLocations[blkIndex].getHosts(),
blkLocations[blkIndex].getCachedHosts()));
}
} else { // not splitable
// 如果不可切,整个文件作为1片!
splits.add(makeSplit(path, 0, length, blkLocations[0].getHosts(),
blkLocations[0].getCachedHosts()));
}
} else {
//Create empty hosts array for zero length files
// 如果文件是个空文件,创建一个切片对象,这个切片从当前文件的0offset起,向后读取0个字节
splits.add(makeSplit(path, 0, length, new String[0]));
}
}
// Save the number of input files for metrics/loadgen
job.getConfiguration().setLong(NUM_INPUT_FILES, files.size());
sw.stop();
if (LOG.isDebugEnabled()) {
LOG.debug("Total # of splits generated by getSplits: " + splits.size()
+ ", TimeTaken: " + sw.now(TimeUnit.MILLISECONDS));
}
return splits;
}