一、概述

客户端通过调用 ClientProtocol.create() 方法创建一个新的文件,这个调用由 NamenodeRpcServer.create()方法响应,create()方法会调用 FSNamesystem.startFileInt(), startFileInt() 方法会级联调用FSNamesystem.startFileInternal() 来创建一个新的文件。

二、实现

2.1. 前置准备

  1. 获取发起请求客户端地址

  2. 检查路径深度

  3. RetryCache 机制

    1
    2
    3
    4
    CacheEntryWithPayload cacheEntry = RetryCache.waitForCompletion(retryCache, null);
    if (cacheEntry != null && cacheEntry.isSuccess()) {
    return (HdfsFileStatus) cacheEntry.getPayload();
    }

    https://blog.csdn.net/androidlushangderen/article/details/106169970

2.2. 创建文件

2.2.1. 校验

  1. 校验副本数是否合法

  2. 校验 blockSize,不能小于 1M

  3. 进行 LAZY_PERSIST 操作(LAZY_PERSIST 可能在节点重启时候丢数据)

  4. 等待加载 fsimage

    1
    waitForLoadingFSImage();
  5. 检查是否安全模式

2.2.2. 创建文件

  1. 获取要添加的 inode

  2. 获取路径

  3. 检查 inode 是否是一个目录,如果是的话抛出异常

  4. 把 Inode 转成 InodeFile

  5. 检查客户端是否有写的权限

  6. 检查是否创建父目录

  7. 检查是否覆盖源文件,如果 true 的话,则删除原来的旧文件。

  8. 文件目录树中添加文件

    1
    2
    3
    4
    5
    6
    7
    Map.Entry<INodesInPath, String> parent = FSDirMkdirOp.createAncestorDirectories(dir, iip,
    permissions);
    if (parent != null) {
    iip = dir.addFile(parent.getKey(), parent.getValue(), permissions,
    replication, blockSize, holder, clientMachine);
    newNode = iip != null ? iip.getLastINode().asFile() : null;//得到创建的节点INodeFile名称
    }
  9. 添加租约

  10. 文件存储策略

2.2.3. 持久化元数据

1
2
3
4
5
6
7
if (!skipSync) {
getEditLog().logSync();
if (toRemoveBlocks != null) {
removeBlocks(toRemoveBlocks);
toRemoveBlocks.clear();
}
}

2.2.4. 审计日志