Skip to content

Same image bytes stored once per conversation/message copy — split media payloads into a content-addressed store (follow-up to #3751/#3748) #3762

Closed

Description

@ranxianglei

标题:同一张图片在每个会话/每条消息里各存一份——把媒体载荷拆成按内容寻址的存储(接 #3751/#3748)

现状

统一存储的 CAS(content 表)以「整条消息 JSON 的 sha256」为键,图片字节(base64)嵌在消息 JSON 里一起存。#3751 的指纹修复落地后,同会话内图片 id 不再重铸、不再每次折叠重写 blob——那是 #3748 冗余增长的大头,已消除。

但跨会话/跨消息的字节级去重仍然没有:

  • 同一张图发进两个会话 → 两边各存一份完整字节(消息 JSON 里文本不同 → hash 不同);
  • 同一会话里同一张图出现两次(两个图片 core)→ 也是各存一份(两条消息 JSON 各嵌一份)。

建议方向

媒体级 CAS:把 CoreMessage 的媒体 sidecar 字段(imageBase64 等)从消息 JSON 中拆出,content 表先存一份纯媒体字节(按 sha256 寻址、refcount 共享),消息 JSON 里放 hash 引用。读取时 join 还原。注意:

收益

多会话重度复图的部署(桌面端贴图工作流、多 agent 共享截图)存储从「份数 × 字节」降到「去重后字节」。#3748 的增长大头已由 #3751 修掉,此项是剩余的跨份冗余。

依赖:#3751(指纹进 id)先行落地——媒体行的 hash 键与 id 指纹同源,避免两套哈希。

Activity

  1. ranxianglei commented on Oct 19, 2026

    @ranxianglei
    OwnerAuthor

    🤖 Powered by ework · qwen3.8-27b

    (ai: vllm-qwen/qwen3.8-27b)

    查重:不重复。 与 #3748(写侧 id 重铸 → 孤儿膨胀,K/H/G 选项)、#3751(K 选项载体:载荷指纹进媒体 id,OPEN 待你批准)同家族但不同层——本项是那两项落地后剩余的跨副本字节冗余(同一像素按消息包装各嵌一份);与 #3463/#3466(保留/GC 半边)、#3400(出口缩放缓存)机制不同。已检索 open/closed issue 与近期 PR,无在途的媒体级 CAS 工作。与 #3748/#3751 互链,各管一层。

    标签:scope/storage / p3(纯存储布局优化、零功能影响;增长主向量由 #3748/#3751 承载,此项单列为剩余优化)。

    代码级核验(master 6f2b113,v0.1.201)

    八问(决策请求)

    1. 是什么问题: CAS 以整条消息 JSON 为键,图片字节在 JSON 内,同一张图随每条包装存一份全量字节。Image message ids re-mint whenever an earlier image leaves the visible tail (membership-based ClusterCounter suffix) — prefix-cache breaks per fold, feeds #3748 storage growth #3751/Shadow ingest mints a new CAS key on every re-ingest: one image payload recorded 56x, 11.06x redundancy, 88.6% of content bytes are refcount=0 orphans #3748 修掉「重铸重复写」后,「同一像素 N 个包装 N 份」仍在。
    2. 什么原因导致的: 存储布局层把「消息」作为存储单元,媒体载荷不是独立一级公民,没有内容寻址共享——是 Phase 1 的设计选择(schema.ts:32-34 明确把 chunks/文件外置列为 deferred design question),不是 bug。
    3. 影响范围与严重程度: 零功能影响(纯磁盘占用)。受益面 = 重度复图部署(桌面贴图工作流、多 agent 共享截图):存储从「份数×字节」降到「去重后字节+小引用」。单列严重度 p3;不做则冗余保留,但主增长向量已被 K/H 覆盖。
    4. 怎么修复的(推荐方案,非选择题):
      • 复用现有 content 表,不新表:媒体行 = 普通 CAS 条目,键 = 解码后规范图像字节的 sha256(与 K 的 id 指纹同源,kernel 落地后导出单一 primitive,host import);消息包装保留 imageMediaType + 新增 imageMediaHash 引用字段。顺带加一个 kind 列(schema v6,幂等 ALTER 照 v2/v5 先例)区分 message/media 行——便宜且符合投影列纪律,利于诊断与未来 GC 启发式。
      • 迁移只走 lazy: messages 表 append-only("UPDATE is a bug",schema.ts:5-7)禁止原地改写存量行;新落盘写拆分形态,旧单体随会话删除自然消亡。
      • 读时 join: loadLegacyView 见 imageMediaHash 即还原对象级字段(digest parity 构造性成立),golden round-trip 测试 + 既有 verifyDrift 抽样统计钉住。
      • refcount 闭环: deleteSession/deleteCheckpoint 同步释放媒体引用(泄漏 = 孤儿病复发,正是本病),测试钉 rc→0→物理删除。
      • 面全覆盖一个 PR: messages log + checkpoint 冻结 blob + CCR envelope 三个面一次覆盖,内部子缺陷清单管理,不拆片。
    5. 是否有回归问题(逐项): digest 对账——构造性安全,门禁靠 golden + verifyDrift 而非信任;refcount 泄漏/孤儿复发——最危险点,release 路径 + 测试闭环;降级兼容——旧 build 读到引用形态包装会在 unified 读面失去图像保真(shadow 模式对模型流量 write-only,legacy .session 文件仍是 source of truth,影响有界,文档标注);append-only 契约——lazy 迁移不动存量行,不违反;wire/模型可见字节——零变化。
    6. 是否破坏缓存: 不涉及。不碰 prefix cache/重试/游标/去重键,模型可见 wire 字节一位不变。
    7. 是否改了设计方向: 不改。是既有「CAS + refcount」契约向媒体载荷的自然延伸,架构/边界/数据流不变。
    8. 是否引入新配置: 无。拆分、lazy 迁移、join 都是默认行为,不加 env/config。

    另有一个产品层问题一并请你拍板:shadow 模式要不要继续镜像图片原始字节?#3748 缓解③曾提 shadow 只留 digest。我的建议:继续镜像(unified storage 存在是为了 replay/export 保真,去重后成本可接受);若 K/H/本项都落地后尺寸压力仍在,回 #3748 再议。

    排期与决策请求

    依赖关系成立:#3751(K)先行——指纹 primitive 在 kernel 侧,落地后 host 直接 import,避免两套哈希。K 目前 OPEN 等你批准(#3751 floor 2 的决策请求上次已答)。H(#3748 CAS 容忍 volatile 字段)与本项正交,可并行推进。本项属 persistence 格式变更(§7.4 human-gated),拍板前不动代码。

    请你拍板: 是否认可「K 先行 → 本项按上述方案实施(复用 content 表 + kind 列 v6 + lazy 迁移 + 三面全覆盖)」?认可后我在 K 合入时直接开实施 PR(引用本 issue)。任何一项想调整(不加 kind 列 / checkpoint 面放二期 / shadow 不镜像字节),说一声我照调。

  2. added 3 commits that reference this issue on Nov 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions