Harden icon cache concurrency (T-606)

This commit is contained in:
ila
2026-07-17 09:38:25 +08:00
parent 8873a5261d
commit f1cc7308db
17 changed files with 835 additions and 60 deletions
+7 -5
View File
@@ -84,11 +84,13 @@ Catalog `icon` v1 是 `sha256:<64 hex>` 内容引用,不是可直接请求的 UR
客户端缓存合约:
1. 请求键为 `(icon digest, DPI)`;DPI 接受 48~768 的整数值。
2. 加载顺序为内存 → 磁盘 → 注入 Fetcher;磁盘文件名为 `<digest>-<dpi>.icon`。
3. 远端和磁盘字节都必须复核 SHA-256,并通过图片解码、2 MiB 默认字节上限与 2048×2048 默认尺寸上限。
4. 只有验证成功的远端字节可用同目录临时文件原子写入磁盘;损坏的普通缓存文件删除后可重新获取,symlink/非普通文件按不安全布局拒绝。
5. 新进程断网时可读取再次验证成功的磁盘缓存;缓存损坏且远端不可用时返回 `no valid icon available`,UI 使用稳定占位图。
6. 后台完成 `IconCache.Load` 与 `DecodeIcon` 后调用 Gio `ApplyIcon`;Layout 只复用内存 `paint.ImageOp`。
2. 加载顺序为有界 memory LRU → 磁盘 → 注入的流式 Fetcher;磁盘文件名为 `<digest>-<dpi>.icon`。memory 默认同时限制为 32 MiB 与 256 个 key,命中提升 LRU recency。
3. 同一 key 的并发 miss 由一个 in-flight leader 执行 disk/fetch/validate/store,等待者复用结果;不同 key 不互相串行。等待者取消只结束自身等待,leader 失败/取消后必须释放 key 供后续重试。
4. Fetcher 返回与请求 context 绑定的 `io.ReadCloser` 和可选声明长度。声明长度超过 2 MiB 默认上限时不读 body;未知或伪造长度仍只读 `maxBytes+1`,所有成功/失败路径都关闭 body。
5. 远端和磁盘字节都必须复核 SHA-256,并通过图片完整解码、2 MiB 默认字节上限与 2048×2048 默认尺寸上限。
6. 只有验证成功的远端字节可用同目录临时文件原子写入磁盘;损坏的普通缓存文件删除后可重新获取,symlink/非普通文件按不安全布局拒绝。
7. 新进程断网时可读取再次验证成功的磁盘缓存;缓存损坏且远端不可用时返回 `no valid icon available`,UI 使用稳定占位图。
8. 后台完成 `IconCache.Load` 与 `DecodeIcon` 后只发布事件;Gio UI goroutine 消费事件后调用 `ApplyIcon`/Invalidate。Layout 只复用内存 `paint.ImageOp`,Catalog 移除 app 时两个 shell 同步剪枝对应 ImageOp。
## 2. 标准软件包协议 v1(ZIP)