2021年山东大学软件工程应用与实践项目——Hadoop源码分析(七)

2021SC@SDUSC

Hadoop源码分析(七)—— NameNode实现(3)

Hadoop源码分析(五)—— NameNode实现(1)
Hadoop源码分析(六)—— NameNode实现(2)

5. FSEditLog 文件系统的编辑日志

FSEditLog 所在的包为org.apache.hadoop.hdfs.server.namenode,该类主要用于 namenode 对 HDFS 的 namespace的修改操作进行日志记录。在namenode中,namespace (指文件系统中的目录树/文件等元数 据信息,但是不包括block信息)是被全部缓存在内存中的,所以一旦namenode重启或者宕机,这些元 数据信息都会丢失。那么,在namenode重启的时候必须要有一种方法来将整个namespace进行重建。namenode的当前的实现是将namespace信息记录到一个叫做fsimage的二进制文件中,当namenode重启的时候则根据读取这个fsimage文件中的信息来重建namespace目录树结构。但是,fsimage始终是磁 盘中的一个文件,不可能时时刻刻都与namenode内存中的数据结构保持同步,而是通过每隔一段时间 来更新一次fsimage文件,以此来保证fsimage跟namenode内存中的namespace的尽量同步。而在一个 新的fsimage和上一个fsimage之间的namenode的操作,都会被记录到editlog文件中,所以namenode 会对应着一个fsimage文件和一个editlog文件。FSEditLog类就是用来管理这个editlog文件的。

5.1 内部类

① EditLogFileOutputStream

EditLogFileOutputStream用于将edit日志记录到本地磁盘中,该类继承自EditLogOutputStream抽象类。EditLogOutputStream 所在的包为 org.apache.hadoop.hdfs.server.namenode ,它进一步继承自 Outputstream 父类。EditLogOutputStream 的源代码如下:

private long numSync;

将输出流中的数据同步到editlog磁盘文件的次数。

private long totalTimeSync;

执行同步操作所花费的总时间。

EditLogOutputStream() throws lOException {
   
numSync = totalTimeSync = 0;
}

在构造方法中将上面的成员变量都初始化为0o

abstract String getName();

该方法用于取得输出流的名称。

abstract public void write(int b) throws IOException;

该方法用于向输出流中写入一个字节。

abstract void write(byte op, Writable ... writables) throws IOException;

该方法用于将一条日志记录写入到该输出流中。其中一条日志记录包括操作名称和一个Writable类 型的参数列表。

abstract void create () throws IOException;

创建并初始化一个新的用于保存日志记录的editlog文件。

abstract public void close() throws IOException;

关闭输出流对象。

abstract void setReadyToFlush() throws IOException;

准备对写入到该输出流中的所有数据执行flush操作。在执行flush的过程中,新的数据仍然可以写 入到该输岀流中。

abstract protected void f lush/kndSync () throws IOException;

将该输出流中所有准备好flush的数据同步到磁盘中。

abstract long length() throws IOException;

取得editlog日志文件的当前长度。取得editlog日志文件长度的目的是为了检查日志文件是否大到 需要需要启动一个检查点进程来进行检査点的处理。

public void flush() throws IOException {
   
numSync++;
long start = FSNamesystem.now();
flushAndSync();
long end = FSNamesystem.now();
totalTimeSync += (end - start);

该方法用于将输出流中的数据刷新同步到磁盘中,同时更新同步统计数据。

接下来看一下EditLogFileOutputStream内部静态类的具体实现:

private File file;
//用于存储日志记录的本地文件。
private FileOutputStream fp;
//存储日志记录的文件输出流对象。
private FileChannel fc;
//执行sync同步操作的文件输出流所对应的文件通道对象。
private DataOutputBuffer bufCurrent;
//当前用于执行写操作的数据缓冲区。
private DataOutputBuffer bufReady;
//当前用于执行flush操作的数据缓冲区。
static ByteBuffer fill = ByteBuffer.allocateDirect(512);
//预分配的大小为512的字节缓冲区。
EditLogFileOutputStream(File name) throws IOException {
   
super ();
file = name;
bufCurrent = new DataOutputBuffer(sizeFlushBuffer);
bufReady = new DataOutputBuffer(sizeFlushBuffer);
RandomAccessFile rp = new RandomAccessFile(name, "rwn");
fp = new FileOutputStream(rp.getFD());
fc = rp.getChannel();
fc.position(fc.size());
}

在构造方法中完成对上面成员变量的初始化。被创建的bufCurrent和bufReady数据缓冲区的大小都 为512KB,之后根据文件的名称来创建一个随机读写文件的RandomAccessFile对象,然后根据 RandomAccessFile对象来进一步创建用于向文件的末尾追加数据的输出流,然后取得输出流对应的通道, 并将输出流通道的位置设置为文件输出流的当前位置。

String getName() {
   
return file.getPath();
}

将用于保存日志记录的文件的路径做为输出流的名称。

public void write(int b) throws IOException {
    bufCurrent.write(b);
}
void write(byte op, Writable ... writables) throws IOException {
   
write(op);
for(
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值