HDFS NameNode保存了两个元数据文件fsimage和edits。如果想要对文件系统进行格式化,应该进行哪些操作呢?按照我们的理解,首先要把已有的fsimage和edits全部删除;其次,重新建立新的fsimage和edits;最后,通知所有的datanode,命令其删除相应的数据。通过阅读HDFS的源程序,我们得知,前两部是HDFS已经实现的;但是,其好像没有通知datanode进行数据删除。为什么会这样,需要进一步阅读程序。下面看一下,HDFS具体是如何进行格式化的。
我们可以看到,HDFS文件系统的格式化是在整个集群启动的时候进行的。在启动的时候,如果用户用户进行格式化操作(命令行-format选项)。NameNode首先根据配置文件,获取fsimage和edits的存放目录(如果hdfs-site.xml没有指定dfs.name.dir的值,则HDFS硬编码默认路径是/tmp/Hadoop/dfs/name)。获取元数据保存路径成功后,对用户进行确认是否格式化相应存储目录下的元数据文件。当用户确认后,调用FSNamesystem.StorageDirectory(其实是整个文件系统的层次化存储,目录树).FSImage进行具体的格式化。
private static boolean format(Configuration conf,
boolean isConfirmationNeeded) throws IOException {
Collection dirsToFormat = FSNamesystem.getNamespaceDirs(conf);
Collection editDirsToFormat = FSNamesystem.getNamespaceEditsDirs(conf);
for (Iterator it = dirsToFormat.iterator(); it.hasNext();) {
File curDir = it.next();
if (!curDir.exists())
continue;
if (isConfirmationNeeded) {
System.err.print("Re-format filesystem in "+curDir+ " ? (Y or N) ");
if (!(System.in.read() == 'Y')) {
System.err.println("Format aborted in " + curDir);
return true;
}
while (System.in.read() != '\n')
; // discard the enter-key
}
}
FSNamesystem nsys = new FSNamesystem(new FSImage(dirsToFormat,
editDirsToFormat), conf);
nsys.dir.fsImage.format();
return false;
}
FSImage首先产生新的layoutVersion(给fsimage文件赋予的一个版本号)、namespaceID(给fsimage赋予的一个id)和cTime(fsimage创建时的时间戳),然后遍历每一个存储目录进行格式化。
public void format() throws IOException {
this.layoutVersion = FSConstants.LAYOUT_VERSION;
this.namespaceID = newNamespaceID();
this.cTime = 0L;
this.checkpointTime = FSNamesystem.now();
for (Iterator it = dirIterator(); it.hasNext();) {
StorageDirectory sd = it.next();
format(sd);
}
}
对于每一个存储目录,FSImage首先删除已有的文件,并创建新的文件。
void format(StorageDirectory sd) throws IOException {
sd.clearDirectory(); // createcurrrentdir
sd.lock();
try {
saveCurrent(sd);
} finally {
sd.unlock();
}
LOG.info("Storage directory " + sd.getRoot()+ " has been successfully formatted.");
}