在《HDFS源码分析EditLog之获取编辑日志输入流》一文中,我们详细了解了如何获取编辑日志输入流EditLogInputStream。在我们得到编辑日志输入流后,是不是就该从输入流中获取数据来处理呢?答案是显而易见的!在《HDFS源码分析之EditLogTailer》一文中,我们在讲编辑日志追踪同步时,也讲到了如下两个连续的处理流程:
4、从编辑日志editLog中获取编辑日志输入流集合streams,获取的输入流为最新事务ID加1之后的数据
5、调用文件系统镜像FSImage实例image的loadEdits(),利用编辑日志输入流集合streams,加载编辑日志至目标namesystem中的文件系统镜像FSImage,并获得编辑日志加载的大小editsLoaded;
可见,我们在获得编辑日志输入流EditLogInputStream的集合streams后,就需要调用FSImage的loadEdits()方法,利用编辑日志输入流集合streams,加载编辑日志至目标namesystem中的文件系统镜像FSImage。而HDFS是如何从编辑日志输入流中读取数据的呢?本文,我们将进行详细的探究!
首先,在加载编辑日志的主要类FSEditLogLoader中,其核心方法loadEditRecords()中有如下一段代码:
while (true) {
try {
FSEditLogOp op;
try {
// 从编辑日志输入流in中读取操作符op
op = in.readOp();
// 如果操作符op为空,直接跳出循环,并返回
if (op == null) {
break;
}
} catch (Throwable e) {
// ...省略部分代码
}
// ...省略部分代码
try {
// ...省略部分代码
long inodeId = applyEditLogOp(op, fsDir, startOpt,
in.getVersion(true), lastInodeId);
if (lastInodeId < inodeId) {
lastInodeId = inodeId;
}
} catch (RollingUpgradeOp.RollbackException e) {
// ...省略部分代码
} catch (Throwable e) {
// ...省略部分代码
}
// ...省略部分代码
} catch (RollingUpgradeOp.RollbackException e) {
// ...省略部分代码
} catch (MetaRecoveryContext.RequestStopException e) {
// ...省略部分代码
}
}
它会从编辑日志输入流in中读取一个操作符op,然后调用applyEditLogOp()方法,将操作符作用于内存元数据FSNamesystem。那么问题来了,这个操作符如何从数据流中被读取并解析的呢?
接下来,我们就看下如何从编辑日志输出流EditLogInputStream中读取一个操作符,我们先看其readOp()方法,代码如下:
/**
* Read an operation from the stream
* @return an operation from the stream or null if at end of stream
* @throws IOException if there is an error reading from the stream
*/
public FSEditLogOp readOp() throws IOException {
FSEditLogOp ret;
// 如果缓存的cachedOp不为null,返回缓存的cachedOp,并将其清空
if (cachedOp != null) {
ret = cachedOp;
cachedOp = null;
return ret;
}
// 如果缓存的cachedOp为null,调用nextOp()进行处理
return nextOp();
}
很简单,如果缓存的cachedOp不为null,返回缓存的cachedOp,并将其清空,如果缓存的cachedOp为null,则调用nextOp()进行处理。而EditLogInputStream中nextOp()是一个抽象方法,我们需要看其子类的实现方法,下面就以EditLogFileInputStream为例,看下其nextOp()方法:
@Override
protected FSEditLogOp nextOp() throws IOException {
return nextOpImpl(false);
}
继续追踪nextOpImpl()方法,代码如下:
private FSEditLogOp nex