Hadoop学习笔记(六)
接着继续上一篇关于FORMAT的分析——
(3)对内存镜像中数据结构的初始化:
初始化工作主要由FSImage的format函数完成,对象主要是FSImage的成员变量:
layoutVersion ---当前软件所处的版本
namespaceID ---HDFS的身份标识,唯一
cTime ---FSImage创建时间
checkpointTime ---Namenode第一次checkpoint的时间
在将成员变量初始化后,会遍历所有的元数据存储目录(在上一步中,已经把备份目录存放到了StorageDIr供这一步使用),一次调用format函数的重载函数,对其进行格式化
public void format() throws IOException {
...
for (Iterator<StorageDirectory> it = dirIterator();it.hasNext();) {
StorageDirectory sd = it.next();
format(sd);
}
}
(4)将内存镜像写入元数据备份目录:
大致分析一下代码的结构————
① 首先是接着上面的format()函数:
这里主要就是那个saveCurrent(sd)函数,用于把当前格式化后的内存镜像保存到sd对象对应的目录中去。
package org.apache.hadoop.hdfs.server.namenode;
FSImage.java
void format(StorageDirectory sd) throws IOException {
sd.clearDirectory();
sd.lock();
try{
saveCurrent(sd);
}
finally{
sd.unlock();
}
....
}
② saveCurrent函数:
其中主要是两个if 判断,如果是fsimage就调用saveFSImage,如果是editslog就调用createEditLogFile在sd指定的目录下创建对应的目录或文件。
protected void saveCurrent(StorageDirectory sd) throws IOException {
File curDIr = sd.getCurrentDir();
....
if (dirType.isOfType(NameNOdeDirType.IMAGE))
saveFSImage(getImageFile(sd,NameNodeFile.IMAGE));
if (dirType.isOfType(NameNOdeDirType.EDITS))
editLog.createEditLogFile(getImageFile(sd,NameNodeFile.EDITS));
sd.write();
}
③ saveFSImage()函数:
先把一些基本信息写入到对应目录下
然后保存当前内存镜像对应根目录下的内容,这个根目录就是之前在FSDirectory构造函数中创建的那个HDFS的rootDir
然后保存根目录下其他的Inode信息
void saveFSImage(File newFile) throws IOException {
...
saveINode2Image(strbuf,fsDir.rootDir,out);
saveImage(strbuf,0,fsDIr.rootDir,out);
...
}
④ saveINode2Image()函数:
用来保存Inode的信息,根据该Inode是目录,链接或者文件作出对应的保存动作
private static void saveINode2Image(ByteBuffer name,INode node,DataOutputStream out) throws IOException{
...
if (node.isDirectory()) {...}
else if (node.isLink()) {...}
else {
INodeFile fileINode = (INodeFile) node;
...
}
}
⑤ saveImage()函数:
判断该Inode是否有子目录或文件,如果没有,结束;
如果有,则获取所有子目录和文件,调用saveInode2Image()来保存对应内容;对应下面代码第一个for循环
如果子INOde中有的是目录,则调用saveImage()函数处理,也就是再一次进入该目录,保存所有INode内容,然后查看是否有子目录;对应第二个for循环
private static void saveImage(ByteBuffer parentPrefix,int prefixLength,INodeDirectory current,DataOutputStream out) throws IOException {
...
if (current.getChildrenRaw() == null) return;
for (INode child:current.getChildren()) {
...
saveINode2Image(parentPrefix,child,out);
}
for (INode child : current.getChildren()) {
if (!child.isDirectory()) continue;
..
saveImage(parentPrefix,newPrefixLength,(INodeDirectory)child,out);
}
}
当fsimage和editlog写入后,准备写入fstime和VERSION——
⑥ write()函数:
format在写入FSImage文件或Edits文件成功后,调用类StorageDirectory的write方法写入fstime和VERSION文件,类StorageDirectory是类Storage的内部成员类,可以访问其所声明的变量和方法。
write首先将类Storage自身属性信息(layoutVersion,storageType,namespaceID,cTime)写入类Properties的实例对象pros中
通过类FSImage重载setFIelds方法写入fstime文件
实例化类RandomAccessFile的对象File,用于对VERSION文件的操作,最后通过file写入属性信息并更新VERSION文件长度
public abstract class Storage extends StorageInfo {
...
public class StorageDirectory {
...
public File getVersionFile() {...}
public void write() thorws IOException {
...
write(getVersionFile());
}
public void write(File to) throws IOException {
Properties props = new Properties();
setFileds(props,this); //注意这里是使用类FSImage重载的父类Storage的setFileds方法,因为在上面实际调用write的sd.write();
RandomAccessFile file = new RandomAccessFile(to,"rws");
...
}
}
protected void setFields (Properties props,StorageDirectory sd) throws IOException {
props.setProperty("layoutVersion",String.valueOf(layoutVersion));
props.setProperty("storageType",storageType.toString());
props.setProperty("namespaceID",String.valueOf(namespaceID));
props.setProperty("cTime",String.valueOf(cTime));
}
}
类FSImage重载父类的setFileds方法,在其方法中,将checkpointTime写入fstime文件
⑦ setFileds()函数:
protected void setFields (Properties props,StorageDirectory sd) throws IOException {
super.setFields(props,sd);
...
writeCheckpointTime(sd);
}
浙公网安备 33010602011771号