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的更多相关文章

  1. hadoop源码剖析--hdfs安全模式

    一.什么是安全模式 hadoop安全模式是name node的一种状态,处于该状态时有种量特性: 1.namenode不接受任何对hfds文件系统的改变操作(即此时整个文件系统处于只读状态): 2.不 ...

  2. hadoop源码剖析--$HADOOP_HOME/bin/hadoop脚本文件分析

    1. $HADOOP_HOME/bin/ hadoop #!/usr/bin/env bash# Licensed to the Apache Software Foundation (ASF) un ...

  3. (升级版)Spark从入门到精通(Scala编程、案例实战、高级特性、Spark内核源码剖析、Hadoop高端)

    本课程主要讲解目前大数据领域最热门.最火爆.最有前景的技术——Spark.在本课程中,会从浅入深,基于大量案例实战,深度剖析和讲解Spark,并且会包含完全从企业真实复杂业务需求中抽取出的案例实战.课 ...

  4. Hadoop源码学习笔记之NameNode启动场景流程二:http server启动源码剖析

    NameNodeHttpServer启动源码剖析,这一部分主要按以下步骤进行: 一.源码调用分析 二.伪代码调用流程梳理 三.http server服务流程图解 第一步,源码调用分析 前一篇文章已经锁 ...

  5. Apache Spark源码剖析

    Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著   ISBN 978-7-121-25420- ...

  6. 《Apache Spark源码剖析》

    Spark Contributor,Databricks工程师连城,华为大数据平台开发部部长陈亮,网易杭州研究院副院长汪源,TalkingData首席数据科学家张夏天联袂力荐1.本书全面.系统地介绍了 ...

  7. Spark源码剖析 - SparkContext的初始化(二)_创建执行环境SparkEnv

    2. 创建执行环境SparkEnv SparkEnv是Spark的执行环境对象,其中包括众多与Executor执行相关的对象.由于在local模式下Driver会创建Executor,local-cl ...

  8. Hadoop源码学习笔记之NameNode启动场景流程一:源码环境搭建和项目模块及NameNode结构简单介绍

    最近在跟着一个大佬学习Hadoop底层源码及架构等知识点,觉得有必要记录下来这个学习过程.想到了这个废弃已久的blog账号,决定重新开始更新. 主要分以下几步来进行源码学习: 一.搭建源码阅读环境二. ...

  9. jQuery之Deferred源码剖析

    一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...

随机推荐

  1. C#规范整理·集合和Linq

    LINQ(Language Integrated Query,语言集成查询)提供了类似于SQL的语法,能对集合进行遍历.筛选和投影.一旦掌握了LINQ,你就会发现在开发中再也离不开它.   开始! 前 ...

  2. Scala IDE里的WorkSheet的使用

    所见即所得的一个工具, 左边编码,右边立即出结果 https://www.cnblogs.com/zlslch/p/6115118.html

  3. [Algorithms] Tree Data Structure in JavaScript

    In a tree, nodes have a single parent node and may have many children nodes. They never have more th ...

  4. LeetCode 205 Isomorphic Strings(同构的字符串)(string、vector、map)(*)

    翻译 给定两个字符串s和t,决定它们是否是同构的. 假设s中的元素被替换能够得到t,那么称这两个字符串是同构的. 在用一个字符串的元素替换还有一个字符串的元素的过程中.所有字符的顺序必须保留. 没有两 ...

  5. Office HPDeskjetD2468 打印机电源灯闪烁不停,打印机不工作怎么办

    怎么处理HP DeskjetD2468 打印机电源灯闪烁不停,打印机不工作? 最佳答案 一般电源灯闪烁时因为你的打印喷头上面的盖子没有盖好,你看看.....盖好之后关机再开 谢谢!

  6. 翻翻git之---有用的欢迎页开源库 AppIntro

    转载请注明出处:王亟亟的大牛之路 今天没有P1.直接进入正题 今天上的是一个帅帅的app滑动介绍页 . 为什么说帅? 作者对自己的内容是这么定义的 Make a cool intro for your ...

  7. python正则方法

    通过正则替换字符串 res=re.sub(正则,newString,srcString)//返回替换后的字符串 res,m=res.subn(正则,newString,srcString)//返回替换 ...

  8. Linq实现SQL in

    比如 Id in (1,2,3) int[] a={1,2,3}; list.Where(x=>a.Contains(x.Id))

  9. kubernetes之pod中断

    系列目录 目标读者: 想要构建高可用应用的应用所有者,因此需要知道pod会发生哪些类型的中断 想要执行自动化(比如升级和自动扩容)的集群管理员. 自愿和非自愿的中断 pod不会自动消息,除非有人(可能 ...

  10. ASP.NET MVC模式——WebPages

    WebPages 示例 123456<html> <body> <h1>Hello Web Pages</h1> <p>The time i ...