issue 正文:
设计目标
减少增量更新的数据量(存储+传输)
基础格式
pax tar 带压缩
压缩要求
分为多个可独立解压的分块,分块之间支持无损连接,即 a.gz+b.gz 可以不经任何后续处理直接解压出 a+b。
配合索引实现部分解压
码流中支持嵌入解压缩时可忽略的内容
可用实现
文件布局
总览
文件头:【Zstd skippable frame】或【解压后长度为 0 的 gzip block 中的 comment】
清单分块
版本清单
增量索引
支持增量更新的版本
后续各个分块的类型、偏移量及长度
当前版本压缩分块
增量清单(二进制 patch 清单、删除文件清单)
当前版本更新且无二进制增量的文件(如 *.png)
n-1版本到当前版本的二进制增量(如 MAA.exe)
n-1版本压缩分块
增量清单
n-1版本更新且无二进制增量的文件
n-2版本到n-1版本的二进制增量
……
n-x版本压缩分块
增量清单
n-x版本更新且无二进制增量的文件
n-x-1版本到n-x版本的二进制增量
后备分块(可选)
当前版本更新且有二进制增量的文件
先前版本更新的文件
更新时删除文件
删除的文件列表存放在增量清单内。
Corner Case
为确保完整解压时不会出现当前版本已删除的文件,不打包中间版本之间新增后删除的文件,即不能通过增量更新包更新到中间版本。
二进制增量更新
增量清单内存放:
需要 patch 的文件路径
patch 数据在压缩包内的名称
patch 类型
patch 前后的文件长度及检验和
patch 后版本
patch 后版本可以是新版本方向的任意版本,生成增量更新包时寻找体积最小的组合。
Corner Case
需要 patch 的文件与某一更新版本一致时,使用特殊 patch 类型标记且不存储 patch 数据。
实现
https://github.com/facebook/zstd/wiki/Zstandard-as-a-patching-engine
% zstd -19 --patch-from b495a16/MAA.exe 2428a46/MAA.exe -o MAA.exe.b495a16-2428a46
long mode automatically triggered
2428a46/MAA.exe : 0.25% ( 40.0 MiB => 103 KiB, MAA.exe.b495a16-2428a46)
using ZstdSharp ;
var dec = new Decompressor ( ) ;
dec . LoadDictionary ( File . ReadAllBytes ( @"b495a16/MAA.exe" ) ) ;
var a = dec . Unwrap ( File . ReadAllBytes ( @"MAA.exe.b495a16-2428a46" ) ) ;
File . WriteAllBytes ( @"2428a46/MAA.exe" , a . ToArray ( ) ) ;
效果
从n-3版本更新到当前版本,只需要根据索引下载n-3版本分块前的数据,即n-3更新到n-2、n-2更新到n-1、n-1更新到当前版本
由于文件头包含清单长度,使用标准 HTTP Range request 时最多产生三个 GET 请求,允许中断一个完整 GET 请求时只需要一个请求。
完整解压含有后备分块的更新包文件,可获得当前版本
对于每个更新通道,服务端仅需保留最新的增量更新包
其他设计
ZIP 格式
不合并文件数据压缩,压缩率低
需要从文件尾读取 central directory,或完全依赖外部索引
外部索引也可以通过 SFX 方式放在 zip 头部,但功能跟 central directory 重复
通过后处理将 central directory 移到头部
兼容性成谜
数据格式定义 语焉不详
central directory 空间效率低
当前 MAA zip 包的 central directory 约 600 KiB
如需继续扩展以存储元数据,则 central directory 将会包含大量重复文本且无法压缩(central directory compression 未见有开源实现,兼容性问题++)
Zip - How not to design a file format.
未解决的问题
非线性版本历史(如 Cherry-pick)
例:
---
config:
gitGraph:
mainBranchName: alpha
showCommitLabel: false
---
gitGraph
branch release
commit tag: "release-0" type: HIGHLIGHT
checkout alpha
commit tag: "alpha-1"
checkout release
merge alpha tag: "beta-1" type: HIGHLIGHT
checkout alpha
commit
commit tag: "alpha-2"
checkout release
merge alpha tag: "release-2" type: HIGHLIGHT
checkout alpha
commit
commit id: "fix" tag: "alpha-3" type: REVERSE
checkout release
cherry-pick id: "fix" tag: "release-2.1"
checkout alpha
commit
commit tag: "alpha-4"
checkout release
merge alpha tag: "beta-4" type: HIGHLIGHT
checkout alpha
commit tag: "alpha-5"
Loading
暂定方案:
本分支版本按时间排序后,非本分支版本寻找位置插入,使得按顺序加权后的总文件变化数量最小。
更新包内的文件级索引
预期用途:修复单个损坏的文件。
结论:谁啊,不认识。
解压时增量清单及二进制增量数据 entry 的处理
增量更新程序不将增量清单及二进制增量数据提取到文件系统。
对于手动解压的情况,二进制增量数据在压缩包内的路径使用约定的临时目录,首次运行时删除。
游戏资源热更
是否也使用此方式,作为独立更新通道更新?
issue 正文:
设计目标
减少增量更新的数据量(存储+传输)
基础格式
pax tar 带压缩
压缩要求
a.gz+b.gz可以不经任何后续处理直接解压出a+b。可用实现
https://www.rfc-editor.org/rfc/rfc1952.html#page-5
https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#skippable-frames
文件布局
总览
更新时删除文件
删除的文件列表存放在增量清单内。
Corner Case
为确保完整解压时不会出现当前版本已删除的文件,不打包中间版本之间新增后删除的文件,即不能通过增量更新包更新到中间版本。
二进制增量更新
增量清单内存放:
patch 后版本可以是新版本方向的任意版本,生成增量更新包时寻找体积最小的组合。
Corner Case
需要 patch 的文件与某一更新版本一致时,使用特殊 patch 类型标记且不存储 patch 数据。
实现
https://github.com/facebook/zstd/wiki/Zstandard-as-a-patching-engine
效果
由于文件头包含清单长度,使用标准 HTTP Range request 时最多产生三个 GET 请求,允许中断一个完整 GET 请求时只需要一个请求。
其他设计
ZIP 格式
未解决的问题
非线性版本历史(如 Cherry-pick)
例:
--- config: gitGraph: mainBranchName: alpha showCommitLabel: false --- gitGraph branch release commit tag: "release-0" type: HIGHLIGHT checkout alpha commit tag: "alpha-1" checkout release merge alpha tag: "beta-1" type: HIGHLIGHT checkout alpha commit commit tag: "alpha-2" checkout release merge alpha tag: "release-2" type: HIGHLIGHT checkout alpha commit commit id: "fix" tag: "alpha-3" type: REVERSE checkout release cherry-pick id: "fix" tag: "release-2.1" checkout alpha commit commit tag: "alpha-4" checkout release merge alpha tag: "beta-4" type: HIGHLIGHT checkout alpha commit tag: "alpha-5"暂定方案:
本分支版本按时间排序后,非本分支版本寻找位置插入,使得按顺序加权后的总文件变化数量最小。
更新包内的文件级索引
预期用途:修复单个损坏的文件。
结论:谁啊,不认识。
解压时增量清单及二进制增量数据 entry 的处理
增量更新程序不将增量清单及二进制增量数据提取到文件系统。
对于手动解压的情况,二进制增量数据在压缩包内的路径使用约定的临时目录,首次运行时删除。
游戏资源热更
是否也使用此方式,作为独立更新通道更新?