HDFS源码分析——格式化

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<File> dirsToFormat = FSNamesystem.getNamespaceDirs(conf);

Collection<File> editDirsToFormat = FSNamesystem.getNamespaceEditsDirs(conf);

for (Iterator<File> 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<StorageDirectory> it = dirIterator(); it.hasNext();) {

StorageDirectory sd = it.next();

format(sd);

}

}

对于每一个存储目录,FSImage首先删除已有的文件,并创建新的文件。

void format(StorageDirectory sd) throws IOException {

sd.clearDirectory(); // create currrent dir

sd.lock();

try {

saveCurrent(sd);

} finally {

sd.unlock();

}

LOG.info("Storage directory " + sd.getRoot()+ " has been successfully formatted.");

}

最终,FSImage保存新的fsimage和edits文件。

protected void saveCurrent(StorageDirectory sd) throws IOException {

File curDir = sd.getCurrentDir();

NameNodeDirType dirType = (NameNodeDirType) sd.getStorageDirType();

// save new image or new edits

if (!curDir.exists() && !curDir.mkdir())

throw new IOException("Cannot create directory " + curDir);

if (dirType.isOfType(NameNodeDirType.IMAGE))

saveFSImage(getImageFile(sd, NameNodeFile.IMAGE));

if (dirType.isOfType(NameNodeDirType.EDITS))

editLog.createEditLogFile(getImageFile(sd, NameNodeFile.EDITS));

// write version and time files

sd.write();

}

最终,我们看一下FSImage是如何保存fsimage文件的。首先存储layoutVersion、namespaceID、整个文件系统中文件和目录的数目、产生时间等基本数据;然后将整个文件系统的INode列表(及所有文件)保存到fsimage;最后保存一些其他数据,具体参见源码:

void saveFSImage(File newFile) throws IOException {

FSNamesystem fsNamesys = FSNamesystem.getFSNamesystem();

FSDirectory fsDir = fsNamesys.dir;

long startTime = FSNamesystem.now();

//

// Write out data

//

DataOutputStream out = new DataOutputStream(new BufferedOutputStream(

new FileOutputStream(newFile)));

try {

out.writeInt(FSConstants.LAYOUT_VERSION);

out.writeInt(namespaceID);

out.writeLong(fsDir.rootDir.numItemsInTree());

out.writeLong(fsNamesys.getGenerationStamp());

byte[] byteStore = new byte[4 * FSConstants.MAX_PATH_LENGTH];

ByteBuffer strbuf = ByteBuffer.wrap(byteStore);

// save the root

saveINode2Image(strbuf, fsDir.rootDir, out);

// save the rest of the nodes

saveImage(strbuf, 0, fsDir.rootDir, out);

fsNamesys.saveFilesUnderConstruction(out);

fsNamesys.saveSecretManagerState(out);

strbuf = null;

} finally {

out.close();

}

LOG.info("Image file of size " + newFile.length() + " saved in "

+ (FSNamesystem.now() - startTime) / 1000 + " seconds.");

}

PS:HDFS NameNode一个主要class之间的关系。

HDFS NameNode的主要入口是class NameNode。NameNode中最主要的变量是FSNamesystem,FSNamesystem代表了整个文件系统的命名空间。它保存了整个文件系统的命名空间FSDirectory。整个文件系统的命名空间FSDirectory中包含了当前文件系统,持久化存储的文件系统状态FSImage。FSImage中包含了对整个文件命名空间操作的日志FSEditLog。

转载于:https://my.oschina.net/sdzzboy/blog/164145

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值