hadoop源码剖析--RawLocalFileSystem
RawLocalFileSystem是hadoop中实现的本地文件系统,在该类中与文件元数据和目录相关的操作,都是通过适配方式适配到java.io.File的对应API来完成的,适配过程简单,代码清晰。
1.文件元数据和目录相关的操作分析
下面主要以mkDirs()方法为例来窥探该类的实现和一些独到之处。
/****************************************************************
* Implement the FileSystem API for the raw local filesystem.
*
* 本地文件系统实现,文件元数据和目录相关的操作都是通过适配到java.io.File的对应API完成的。
*****************************************************************/
public class RawLocalFileSystem extends FileSystem {
static final URI NAME = URI.create("file:///"); //本地文件系统的uri scheme
private Path workingDir; /**
* Creates the specified directory hierarchy. Does not
* treat existence as an error.
*/
//递归创建目录,是个幂等操作
public boolean mkdirs(Path f) throws IOException {
Path parent = f.getParent();
File p2f = pathToFile(f); //如果父目录为空,试图先创建父目录
//通过File创建目录,并判断成功创建目录
return (parent == null || mkdirs(parent)) &&
(p2f.mkdir() || p2f.isDirectory());
} /** {@inheritDoc} */
//递归创建目录,并为目录设置访问权限(通过调用shell的"chmod "命令来完成的)
//问答:奇怪java的文件操作中没有提供chmod的api吗???查看java.io.File后发现提供了相应的api,
//但控制粒度太粗了,相关api为:setReadOnly,setWritable,setReadable,setExecutable。对用户权限的控制只到了owner和other的区分对待,没有“chmod ”控制的精细
@Override
public boolean mkdirs(Path f, FsPermission permission) throws IOException {
boolean b = mkdirs(f);
setPermission(f, permission);
return b;
}
再看一下RawLocalFileSystem中的一个内部类RowLocalFileStatus:
static class RawLocalFileStatus extends FileStatus {
/* We can add extra fields here. It breaks at least CopyFiles.FilePair().
* We recognize if the information is already loaded by check if
* onwer.equals("").
*/
private boolean isPermissionLoaded() {
return !super.getOwner().equals("");
}
RawLocalFileStatus(File f, long defaultBlockSize, FileSystem fs) {
super(f.length(), f.isDirectory(), 1, defaultBlockSize,
f.lastModified(), new Path(f.getPath()).makeQualified(fs));
}
@Override
public FsPermission getPermission() {
if (!isPermissionLoaded()) {
loadPermissionInfo();
}
return super.getPermission();
}
//使用'ls -ld'命令来获取权限信息
private void loadPermissionInfo() {
IOException e = null;
try {
StringTokenizer t = new StringTokenizer(
FileUtil.execCommand(new File(getPath().toUri()),
Shell.getGET_PERMISSION_COMMAND()));
//expected format
//-rw------- 1 username groupname ...
String permission = t.nextToken();
if (permission.length() > 10) { //files with ACLs might have a '+'
permission = permission.substring(0, 10);
}
setPermission(FsPermission.valueOf(permission));
t.nextToken();
setOwner(t.nextToken());
setGroup(t.nextToken());
} catch (Shell.ExitCodeException ioe) {
if (ioe.getExitCode() != 1) {
e = ioe;
} else {
setPermission(null);
setOwner(null);
setGroup(null);
}
} catch (IOException ioe) {
e = ioe;
} finally {
if (e != null) {
throw new RuntimeException("Error while running command to get " +
"file permissions : " +
StringUtils.stringifyException(e));
}
}
}
通过以上两段代码可以看出hadoop的本地文件系统的实现,在利用java语言提供的File类的基础上,做了一些适合自身的变化来达到目标。调用linux的shell命令,需要在linux系统中创建一个新的java虚拟机而消耗大量的资源。
2. 文件的读分析
RawLocalFileSystem使用LocalFSFileInputStream和LocalFSFileOutputStream进行读写。
/*******************************************************
* For open()'s FSInputStream
*******************************************************/
//本地文件系统读取流
class LocalFSFileInputStream extends FSInputStream {
FileInputStream fis; //文件读取流
private long position; //记录当前读取的数据在文件中的位置 public LocalFSFileInputStream(Path f) throws IOException {
this.fis = new TrackingFileInputStream(pathToFile(f)); //实际使用的是文件读取流是TrackingFileInputStream
} //系统文件当前位置
public void seek(long pos) throws IOException {
fis.getChannel().position(pos);
this.position = pos;
} //获取位置
public long getPos() throws IOException {
return this.position;
} //定位到新的block(本地文件系统没有这样的功能,所以简单返回失败)
public boolean seekToNewSource(long targetPos) throws IOException {
return false;
} /*
* Just forward to the fis
*/
//获取剩余可读或可跳过的字节数
public int available() throws IOException { return fis.available(); }
//关闭输入流,并释放系统分配的资源
public void close() throws IOException { fis.close(); }
public boolean markSupport() { return false; } //read()方法需要随时更新position,以保证getPos()能返回正确的值
public int read() throws IOException {
try {
int value = fis.read();
if (value >= 0) {
this.position++; //更新文件当前位置
}
return value;
} catch (IOException e) { // unexpected exception
throw new FSError(e); // assume native fs error
}
} public int read(byte[] b, int off, int len) throws IOException {
try {
int value = fis.read(b, off, len);
if (value > 0) {
this.position += value;
}
return value;
} catch (IOException e) { // unexpected exception
throw new FSError(e); // assume native fs error
}
} public int read(long position, byte[] b, int off, int len)
throws IOException {
ByteBuffer bb = ByteBuffer.wrap(b, off, len);
try {
return fis.getChannel().read(bb, position);
} catch (IOException e) {
throw new FSError(e);
}
} public long skip(long n) throws IOException {
long value = fis.skip(n);
if (value > 0) {
this.position += value;
}
return value;
}
}
可以看到LocalFSFileInputStream类实际使用的读流是TrackingFileInputStream
//重写了FileInputStream中的所有read方法,提供文件读取字节数的统计功能。
//TrackingFileInputStream使用修饰器模式
class TrackingFileInputStream extends FileInputStream {
public TrackingFileInputStream(File f) throws IOException {
super(f);
} public int read() throws IOException {
int result = super.read();
if (result != -1) {
statistics.incrementBytesRead(1);
}
return result;
} public int read(byte[] data) throws IOException {
int result = super.read(data);
if (result != -1) {
statistics.incrementBytesRead(result);
}
return result;
} public int read(byte[] data, int offset, int length) throws IOException {
int result = super.read(data, offset, length);
if (result != -1) {
statistics.incrementBytesRead(result);
}
return result;
}
}
那么RawLocalFileSystem和LocalFSFileInputStream是如何对接起来进行读操作的呢,当然还是和java的api一致(使用open()和create()方法来创建LocalFSFileInputStream)。下面以LocalFSFileInputStream的open()方法为例进行分析:
public FSDataInputStream open(Path f, int bufferSize) throws IOException {
if (!exists(f)) {
throw new FileNotFoundException(f.toString());
}
return new FSDataInputStream(new BufferedFSInputStream( //包装LocalFSFileInputStream
new LocalFSFileInputStream(f), bufferSize));
}
public class FSDataInputStream extends DataInputStream
implements Seekable, PositionedReadable, Closeable { public FSDataInputStream(InputStream in)
throws IOException {
super(in);
if( !(in instanceof Seekable) || !(in instanceof PositionedReadable) ) {
throw new IllegalArgumentException(
"In is not an instance of Seekable or PositionedReadable");
}
} public synchronized void seek(long desired) throws IOException {
((Seekable)in).seek(desired);
} public long getPos() throws IOException {
return ((Seekable)in).getPos();
} public int read(long position, byte[] buffer, int offset, int length)
throws IOException {
return ((PositionedReadable)in).read(position, buffer, offset, length);
} public void readFully(long position, byte[] buffer, int offset, int length)
throws IOException {
((PositionedReadable)in).readFully(position, buffer, offset, length);
} public void readFully(long position, byte[] buffer)
throws IOException {
((PositionedReadable)in).readFully(position, buffer, 0, buffer.length);
} public boolean seekToNewSource(long targetPos) throws IOException {
return ((Seekable)in).seekToNewSource(targetPos);
}
}
获取到读流后就可以调用流的读取方法进行读取了。
3. 文件的写分析
至于写操作,还是和java中的写保持一致的,支持append和随机写两种方式。
hadoop源码剖析--RawLocalFileSystem的更多相关文章
- hadoop源码剖析--hdfs安全模式
一.什么是安全模式 hadoop安全模式是name node的一种状态,处于该状态时有种量特性: 1.namenode不接受任何对hfds文件系统的改变操作(即此时整个文件系统处于只读状态): 2.不 ...
- hadoop源码剖析--$HADOOP_HOME/bin/hadoop脚本文件分析
1. $HADOOP_HOME/bin/ hadoop #!/usr/bin/env bash# Licensed to the Apache Software Foundation (ASF) un ...
- (升级版)Spark从入门到精通(Scala编程、案例实战、高级特性、Spark内核源码剖析、Hadoop高端)
本课程主要讲解目前大数据领域最热门.最火爆.最有前景的技术——Spark.在本课程中,会从浅入深,基于大量案例实战,深度剖析和讲解Spark,并且会包含完全从企业真实复杂业务需求中抽取出的案例实战.课 ...
- Hadoop源码学习笔记之NameNode启动场景流程二:http server启动源码剖析
NameNodeHttpServer启动源码剖析,这一部分主要按以下步骤进行: 一.源码调用分析 二.伪代码调用流程梳理 三.http server服务流程图解 第一步,源码调用分析 前一篇文章已经锁 ...
- Apache Spark源码剖析
Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著 ISBN 978-7-121-25420- ...
- 《Apache Spark源码剖析》
Spark Contributor,Databricks工程师连城,华为大数据平台开发部部长陈亮,网易杭州研究院副院长汪源,TalkingData首席数据科学家张夏天联袂力荐1.本书全面.系统地介绍了 ...
- Spark源码剖析 - SparkContext的初始化(二)_创建执行环境SparkEnv
2. 创建执行环境SparkEnv SparkEnv是Spark的执行环境对象,其中包括众多与Executor执行相关的对象.由于在local模式下Driver会创建Executor,local-cl ...
- Hadoop源码学习笔记之NameNode启动场景流程一:源码环境搭建和项目模块及NameNode结构简单介绍
最近在跟着一个大佬学习Hadoop底层源码及架构等知识点,觉得有必要记录下来这个学习过程.想到了这个废弃已久的blog账号,决定重新开始更新. 主要分以下几步来进行源码学习: 一.搭建源码阅读环境二. ...
- jQuery之Deferred源码剖析
一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...
随机推荐
- leetcode 题解 || Remove Nth Node From End of List 问题
problem: Given a linked list, remove the nth node from the end of list and return its head. For exam ...
- select中分割多组option
<optgroup style="color:gray; font-style:normal" label="——雪佛兰(五菱)——"></o ...
- 使mysql按中文字段排序
http://ourmysql.com/archives/391 测试后我发现,gbk不仅对字符内容是按拼音排序的,对数字也是一样,使用时需注意! 另外一篇文章: MySQL按中文拼音排序
- POJ 3580(SuperMemo-Splay区间加)[template:Splay V2]
SuperMemo Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 11384 Accepted: 3572 Case T ...
- YUV格式
http://blog.csdn.net/u011270282/article/details/50696616 http://blog.csdn.net/acs713/article/details ...
- 两个经典的文件IO程序示例
前言 本文分析两个经典的C++文件IO程序,提炼出其中文件IO的基本套路,留待日后查阅. 程序功能 程序一打印用户指定的所有文本文件,程序二向用户指定的所有文本文件中写入数据. 程序一代码及其注释 # ...
- Android-Bundle的说明和用法
1.Bundle类的作用 Bundle类是一种数据载体,类似于Map,用于存放key-value名值对形式的值.相对于Map,它提供了各种常用类型的putXxx()/getXxx()方法, 如:put ...
- iOS开发之加载、滑动翻阅大量图片优化解决方案
本文转载至 http://mobile.51cto.com/iphone-413267.htm 今天分享一下私人相册中,读取加载.滑动翻阅大量图片解决方案,我想强调的是,编程思想无关乎平台限制.我要详 ...
- spring源码解析——2容器的基本实现(第2版笔记)
感觉第二版写的略潦草,就是在第一版的基础上加上了新的流行特性,比如idea,springboot,但是,潦草痕迹遍布字里行间. 虽然换成了idea,但是很多截图还是eclipse的,如果不是看了第一版 ...
- mac gem命令
$ gem sources -r https://rubygems.org/ (移除旧版本的镜像,如果你不知道你电脑上目前用的是什么镜像,可用 $ gem sources -l 来查看) $ g ...