04

私有工作只会一次性成为共享历史。

工作区会话围绕一个稳定文件系统视图协调命令。终结时捕获私有更改,将每条路径与当前 head 解决冲突,然后发布一个不可变层,或拒绝全部内容。

会话契约

私有执行和共享状态之间的编排边界。

层栈拥有持久历史记录,命名空间进程拥有执行边界,OverlayFS 拥有可写视图。工作区会话将句柄组合在一起,并决定生命周期边缘何时可以交叉。

租约
固定用作会话的发布基础的不可变层栈视图。
holder + 命名空间 FD
保持用户、挂载、PID 和可选网络边界处于活动状态。
覆盖层句柄
命名为upperdir、workdir,并合并了此会话拥有的工作区。
准入闸门
序列化生命周期边缘,而不序列化承认的 命令运行时。
命令账本
跟踪哪些命名空间执行仍属于会话。
终结政策
保留显式会话或发布,然后保留 销毁 为隐式会话。
创建与回滚

向前建设,向后补偿。

会话的创建跨越了存储、进程、网络、挂载、持久性和登记表的边界。故障永远不会使后来的资源保持活动状态,同时默默地删除早期的所有者。

  1. 01

    获取租约

    在任何运行时状态存在之前固定活动的 manifest。

    失败时

    发布租约

  2. 02

    创建草稿

    分配upperdir、workdir、运行目录和会话标识。

    失败时

    删除运行树

  3. 03

    生成 holder

    创建命名空间、捕获FD,并准备可选的隔离网络。

    失败时

    杀holder+免费网络

  4. 04

    挂载 OverlayFS

    使用私有 upperdir 投影 已租借 下链。

    失败时

    命名空间拆卸

  5. 05

    Persist + register

    写入管理器状态,准备cgroup叶子,然后插入活动会话。

    失败时

    销毁或表面回滚故障

准入闸门+ 命令账本

将决策序列化,而不是 命令运行时。

每个会话一个互斥锁可保护 准入、完成、终结、文件操作、重新挂载和受保护的 销毁。互斥体在附加 命令 后被释放,因此承认 命令 仍然并发执行。

一个 命令 生命周期

  1. 01

    锁闸门

    解决实时会话并阻止并发 终结、重新挂载、文件操作或 销毁。

  2. 02

    插入账本条目

    在 runner 完成之前附加命名空间执行 ID。

  3. 03

    Launch + attach

    预留执行能力,启动runner,连接其终端输出。

  4. 04

    发布闸门

    命令 在其生命周期边缘为 已提交后并发运行。

  5. 05

    完成

    删除账本条目;空的账本可以将会话转换为 终结。

01

活动中

命令可以录取;账本耗尽后仍保留显式会话。

02

敲定

当捕获、发布和隐式拆解在闸门下运行时,没有新的工作进入。

03

FinalizeFailed

会话仍然是可摧毁的,但不能安静地恢复到正常的准入。

捕获+发布管道

upperdir 将环路闭合回到层栈。

捕获读取实际的 OverlayFS upperdir。 Planning 仅使用不可变的会话基数;冲突解决移至 写入锁 下方,并与当前活动的 head 进行比较。

  1. 01

    捕获

    遍历 upperdir 并从内核 OverlayFS 元数据派生写入、符号链接、whiteout 和不透明目录。

  2. 02

    规划

    根据会话的不可变 已租借 基础路由路径并记录预期内容 指纹。

  3. 03

    Lock + resolve

    获取层栈写入锁 并将实际 指纹 与当前活动的 head 进行比较。

  4. 04

    合并或拒绝

    接受相等路径、三向合并符合条件的文本,或拒绝冲突时的完整发布。

  5. 05

    Commit + attribute

    提升一阶段的不可变层,前置 manifest,然后附加所有权证据。

依靠内核元数据,而不是文件名惯例

捕获可识别设备或 xattr 元数据中的 OverlayFS whiteout 和不透明目录。用户创建的文件名以 .wh. 不会被默默地重新解释为删除标记。

乐观并发控制

允许陈旧的清单。冲突的路径则不然。

每个更改的源路径都携带来自 已租借 基础的预期 指纹。在写入锁下,层栈从当前的head解析出实际的指纹。这种每路径比较(而不是 manifest 新鲜度)才是真正的并发控制。

三个输入
basesession’s leased bytes
activecurrent head bytes
commandcaptured upperdir bytes

符合条件的文本在行区域上合并。运行时发出干净的字节和结构起源范围 - 绝不冲突标记。

head 不变

expected = actual

接受命令变更

不相交的文本编辑

合并(基础,head,命令)

发布合并字节

重叠编辑

不同的替换区域

拒绝源冲突

非文字或超大尺寸

合并不合格

拒绝,无冲突标记

忽略规则路由归属;他们不只是简单地删除更改。源路由路径接收 指纹 验证和线路来源,而忽略的路径使用来自会话基本策略的整体归因。

原子发布

首先是耐用的有效载荷。 manifest 可见度最后。

解析后的 更改集 被写入随机数 暂存 目录中。文件和目录在重命名之前同步;在新的不可变层激活之前立即重新检查 manifest。

  1. 01

    写暂存

    在唯一的临时层目录下实现每个已解决的更改。

  2. 02

    Sync + rename

    fsync 有效负载和树,然后以原子方式将 暂存 重命名为其最终的 L* 路径。

  3. 03

    复查head

    如果解决后 manifest 发生更改,请删除升级的层并报告冲突。

  4. 04

    前置 manifest

    先用L*写下一个版本;只有这样新租约才能观察到它。

空或字节相同的输出是无操作。拒绝不会产生部分层,并且会在触发 终结 的 命令 上显示。

成本与归因

协调随着状态的改变而变化,而不是基本结帐。

共享基础保持固定且不可变。会话设置可通过下链元数据进行扩展; 终结 随着 已捕获路径和受影响的字节进行扩展。

操作主导界原因
会话创建θ(L)构建并固定 L-层下链条;没有 θ(B) 基础副本。
捕获O(C log C + 访问的字节数)步行并确定地排序 C upperdir 变化。
解决O(C·L·P + H)找到通过 L层的 C 路径,并对 H 受影响的字节进行散列或合并。
提交O(改变的字节+manifest)编写一棵 暂存 树,同步、重命名和添加元数据。

归因遵循解决结果

合并记录最终行范围是否来自活动历史记录或 命令。在提交之后,这些源被映射到运行时所有者,并附加到可压缩的层存储之外。

相关层栈模型

文件-操作怪