# 磁盘格式、提交和恢复

`disk` 是 native 包。树和恢复判断均由 MoonBit 完成，`disk/io.c` 只实现系统文件原语。
这是单进程单线程使用的可变对象；同目录的其他进程不能同时打开日志。

## 文件和节点坐标

创建时要求目标目录不存在，已存在的目录不会被覆盖。目录内有：

| 文件 | 内容 |
| --- | --- |
| `payload` | 按顺序连接的原始记录字节；允许空记录 |
| `index` | 每条 16 字节，小端 UInt64 偏移和长度 |
| `nodes` | 依次写叶哈希和该次追加完成的父节点，每节点 32 字节 |
| `state` | 已提交载荷长度及 compact frontier，含版本和校验和 |
| `lock` | OS 锁的载体，文件本身可以一直存在 |
| `state.tmp` | 检查点替换的暂存文件，重启忽略未提交版本 |

设追加 `n` 叶后已完成的节点数为 `F(n)=2n-popcount(n)`。
高度 `h`、横向坐标 `i` 的节点结束于 `x=(i+1)×2^h`，在 `nodes` 中的序号是
`F(x−1)+h`。因此只需偏移读取一个节点，无须加载完整索引或历史叶子。

节点与历史证明通过公开的 `*_from_reader` API 生成，也可换成调用方自己的存储。
构树前沿仅 O(log n) 个哈希，磁盘批次最多 4096 条；不会把全文件读入内存。
历史包含/一致性生成保守为 O(log² n) 次节点操作；区间证明只读取两侧 compact gaps。
`audit` 为全量线性读取，逐条校验记录、偏移连续性及所有已完成节点，再核对最终根。

## 提交顺序

1. 检查整批条数、字节和偏移限额，不通过时日志保持可用且不写文件。
2. 在内存形成本批载荷、索引、新节点和新前沿。
3. 写入三个文件的尾部，分别同步到 OS。
4. 将完整新状态写入 `state.tmp` 并同步。
5. 替换 `state`：Linux `rename` 后同步目录；Windows 使用 Unicode 路径的
   `MoveFileExW(REPLACE_EXISTING | WRITE_THROUGH)`。
6. 更新当前对象的已提交状态并返回快照。

一旦开始写文件后发生错误，对象会被标记为不可继续操作。调用方须关闭、重新打开，
以重新读取的快照判断本批是否已提交；不能根据异常直接假定本批一定未提交。
六阶段白盒测试覆盖三个文件写入后、数据同步后、状态替换前、替换后的失败。

## 恢复

`open` 首先获取独占锁，读取和检查状态版本、长度、校验和及 canonical frontier。
先检查全部数据文件没有短于已提交长度，再验证保存的前沿与节点文件所得根相同。
以上检查成功后，才截去超出已提交长度的尾部并同步。损坏、缺失或截短的已提交状态
不会被悄悄当作旧版本或空日志恢复。

锁使用 Linux `flock` 或 Windows `LockFileEx`，进程终止自动释放，无须删除旧锁文件。
磁盘日志持有的描述符应由调用方显式 `close`。不支持多个线程同时使用同一对象。

快速恢复只验证前沿，不能检测所有历史块的损坏。需要全面校验时执行 `audit`；
`read_entry` 也会核对读出的记录与对应叶哈希。历史证明最终必须针对外部可信快照验证。

## 上限

- 每次追加最多 4096 条、16 MiB 载荷；单条最多 1 MiB。
- 理论叶数上限 `2^56−1`，用于保证所有文件偏移在有符号 64 位范围内；
  实测规模为 7 万和 14 万叶，不将理论上限当作容量实测。
- 载荷文件长度最多 `2^63−1` 字节；目录必须由调用方管理，不能由不可信第三方同时替换文件。
- 便携 `MemoryLog` 仍限 65,536 叶、64 MiB；`CompactRange` 流式构树不限于该内存日志规模，
  但只保留前沿，不能单独提供已丢弃历史的证明。

## 耐久性范围

支持本地文件系统与单写者。文件同步和原子替换不能替代文件系统、磁盘和电源的保证；
本项目没有做物理断电、网络文件系统、恶意内核或硬件缓存失效认证。
测试包括真实杀死写进程、重启、状态损坏、已提交文件截短及未提交尾部回收。
所有恢复用校验和都用于损坏检查，不是签名或身份认证。

CLI 的日志提交与另一个输出文件之间不提供跨文件事务。`--out` 会先检查已有目标，
并在最终写入时排他创建；若提交后输出出现 I/O 故障，应先检查日志快照再决定是否重试追加。

## 格式兼容

磁盘状态以 `MADL` 和版本字节 `1` 开头，包含小端载荷长度、`MACR/1` frontier 和
SHA-256 域分离校验值。compact checkpoint 包含起止索引、规范子树列表及校验值。
此格式为 MoonAppend 自定义的本地存储格式，不冒充 RFC 或 Go/Python 库的存储格式。
