Fuchsia 中的 BlobFS 文件系统以透明方式压缩文件, 磁盘空间。BlobFS 支持多种不同的压缩策略, zstd 是默认值。
文件压缩有一个缺点,那就是它会阻止随机访问 文件。对于大多数压缩算法,都必须从 然后解压缩即可访问单个字节。
对于 BlobFS,当文件是按需分页时,这是一个特殊的挑战。需求 分页可将文件部分加载到内存中,从而节省系统内存 内存。完整文件压缩可防止文件只加载一部分。
Fuchsia 将压缩文件拆分为可独立运行的帧 文件。这使得 BlobFS 能够对压缩文件进行需求分页, 因为文件可以部分加载和解压缩。
本文档介绍了分块压缩格式的设计, 解释了它在 Fuchsia 中的用途。
设计目标和非目标
以下列出了分块压缩设计的动机 格式和库:
随机访问解压缩。必须能够独立 解压缩数据帧,而无需解压缩整个文件。
柔性环境解压缩 API。该库旨在 因此客户端可以精确控制哪些 进行解压缩的帧。这支持需求分页等使用场景 客户端 (BlobFS) 拥有有关访问模式的更多信息, 通过解压缩特定帧来精确控制预读和预提取。
这与管理程度更高的 API 不同 帧包含哪些已解压缩的字节。
可配置的帧大小。必须能够将 解压缩的数据帧,以满足不同应用场景和不同需求 要求。
灵活的压缩布局。此格式支持更具特色的帧 布局,例如具有不统一的框架尺寸或对齐的框架 以适应将来需要更多 灵活性。例如,非统一的帧尺寸可用于改进 数据存放区域:将一起读取的数据分成一组较小的数据, 或更大的帧。
与 zstd 相当的压缩比。 由于 zstd 是 BlobFS 当前的默认压缩算法, zstd 的压缩比是基准 用于对分块压缩库进行基准测试开销 因此必须尽量减少额外的元数据
可配置的压缩积极性。必须能够用于 降低压缩速度,从而获得更好的压缩比。
跨平台库。用于压缩和解压缩的库 分块压缩归档必须在 Fuchsia 和 编译主机(例如 Linux)中运行,以便在编译过程中使用 工具链。这是在构建时压缩文件所必需的,例如 。
以下是非目标:
- 与 zstd 的格式级别兼容性。分块压缩归档是 与 zstd 和常规 zstd 工具不具有格式兼容 不适用于分块压缩归档
分块压缩
归档文件格式
分块归档包含一个标头,该标头后跟零个或多个 zstd 帧。
标题
标头描述存档格式,并包含一个还原表,该表用于 将压缩帧映射到解压缩空间。
0 1 2 3 4 5 6 7
+-----+-----+-----+-----+-----+-----+-----+-----+
0 | Magic Number |
+-----+-----+-----+-----+-----+-----+-----+-----+
8 | Version | Reserved | Num Frames | // Reserved must be zero.
+-----+-----+-----+-----+-----+-----+-----+-----+
16 | Header CRC32 | Reserved | // Reserved must be zero.
+-----+-----+-----+-----+-----+-----+-----+-----+
24 | Reserved | // Reserved must be zero.
+-----+-----+-----+-----+-----+-----+-----+-----+
32 | |
40 | Seek Table |
48 | Entry |
56 | |
+-----+-----+-----+-----+-----+-----+-----+-----+
.. | |
.. | Seek Table |
.. | Entry |
.. | |
+-----+-----+-----+-----+-----+-----+-----+-----+
“Header CRC32”基于整个标头计算,包括查找 表格。
跳转表
每个跳转表条目描述压缩文件中的 空间,以及数据在解压缩后扩展到的什么位置。
+-----+-----+-----+-----+-----+-----+-----+-----+
0 | Decompressed Offset |
+-----+-----+-----+-----+-----+-----+-----+-----+
8 | Decompressed Size |
+-----+-----+-----+-----+-----+-----+-----+-----+
16 | Compressed Offset |
+-----+-----+-----+-----+-----+-----+-----+-----+
24 | Compressed Size |
+-----+-----+-----+-----+-----+-----+-----+-----+
还原表条目在解压缩空间中是连续的,但可能 不连续的。这是为了支持添加对齐和 填充,以提高存储空间访问效率。
一个跳转表最多可容纳 1023 个条目(产生 32KiB 标头)和 必须包含至少 1 个条目(这将生成 64 字节的标头)。通常情况下 压缩帧紧跟在定位表之后(但此格式支持 从超过定位表末尾的任意偏移量开始的压缩帧)。
还原表不变量
I0:第一个寻道表条目的解压缩偏移量必须为 0。
I1:第一个定位表条目的压缩偏移量必须大于 或 与标头尺寸相同
I2:每个条目的解压缩偏移量必须等于 上一帧(即到上一帧的解压缩后偏移 + 长度)。
I3:每个条目的压缩偏移量必须大于或等于末尾 (即上一帧的压缩后的大小) 偏移 + 长度)。
I4:每个条目的解压缩和压缩长度都必须为非零值。
I5:任何压缩帧都不得超过文件末尾。
压缩帧
文件中的每个压缩帧都是一个常规的 zstd 压缩帧。给定 帧会映射到解压缩文件中某个连续的字节块。
文件中未包含跳转表的任何字节范围都会被忽略。
不要求每一帧数据具有相同的解压缩大小, 但当前的压缩实现方式是将输入数据拆分为 相等的帧。在压缩过程中,可以配置帧的大小。
随机访问解压缩
跳转表用于查找包含给定解压后的帧 范围。在请求解压缩文件中的特定范围时,一个或多个 必须加载和解压缩压缩帧。
例如,请考虑以下包含三个帧的文件:
Decompressed Space Compressed Space
+-----------------+ +--------------+
| | <-------- | |
| | | +--------|
| | +-----+ |
+-----------------+ +------ | |
| | <-+ +--------------+
| | +-- | |
| | | +--------------=
+-----------------+ |
| | <-----+
| +---------|
+-------+
要访问单个帧中的字节范围,只需解压缩 对应的压缩帧:
Decompressed Space Compressed Space
+-----------------+ +--------------+
| | <-------- |xxxxxxxxxxxxxx|
| xxxxxxxx | |xxxxx+--------|
| | +-----+ |
+-----------------+ +------ | |
| | <-+ +--------------+
| | +-- | |
| | | +--------------=
+-----------------+ |
| | <-----+
| +---------|
+-------+
涵盖多个解压缩帧的范围需要解压缩 多个压缩帧:
Decompressed Space Compressed Space
+-----------------+ +--------------+
| | <-------- |xxxxxxxxxxxxxx|
| | |xxxxx+--------|
| xxx| +-----+xxxxxxxx|
+-----------------+ +------ |xxxxxxxxxxxxxx|
|xxxx | <-+ +--------------+
| | +-- | |
| | | +--------------=
+-----------------+ |
| | <-----+
| +---------|
+-------+
在 BlobFS 中使用
在 BlobFS 中,文件使用分块压缩库进行压缩, 实现随机访问和需求分页。
目前,只有在启用需求分页时才能使用随机访问。有需求来源 分页功能已停用,BlobFS 将首先加载和解压缩整个文件 在内存中有文件句柄时,在内存中缓冲文件。
启用需求分页后,BlobFS 会按原样延迟加载文件的某些部分 。BlobFS 将自己注册为 使用 zx_pager_create 系统调用。当 在 VMO 中访问不存在的页面时,会发生页面错误,这导致 BlobFS 标识名。
BlobFS 会查找包含目标网页的解压缩帧,以及 解压缩每一帧。解压每一帧后,验证数据 并通过 zx_pager_supply_pages 系统调用。