Files
Agent-System/.doc/audit/2026-09-21-document-storage-cow-status.md
T

3.1 KiB
Raw Blame History

title, status, created, updated, severity
title status created updated severity
文档存储 CoW(写时复制)现状审计 done 2026-09-21 2026-09-21 low

文档存储 CoW(写时复制)现状审计

背景

用户诉求:上传文档要「几个人传同一份只存一份」,涉及可编辑文档时「考虑 CoW,写入时复制」。本审计确认系统当前的去重与写时复制实现状态,并明确本次收口补齐了什么。

现状分析

系统存在两套内容存储,均已采用内容寻址(Content-Addressed Storage, CAS),天然满足去重与 CoW 语义:

1. 二进制资产:internal/storage/cas.go

  • 物理对象表 storage_blobs 以 sha256 为主键,ref_count 记录引用数。
  • 上传命中相同 sha 时(cas.go storeFileDB)不写第二份物理文件,仅 ref_count + 1,并新建一条 file_references 逻辑引用。→ 满足「多人传同一文档只存一份」。
  • 文件路径 blobs/<xx>/<yy>/<sha>.bin 由内容 hash 唯一决定;StoreFile 对已存在 blob 只读不覆写(命中去重分支直接返回)。内容变化 → hash 变化 → 新路径新文件。→ 即 CoW:修改等价于写入新对象,旧对象不被就地改写。

2. 可编辑文档正文:internal/docrevision/pg_store.go

  • document_content_blobs 以 content_sha256 为键,ensureBlobTX 使用 INSERT ... ON CONFLICT DO NOTHING(pg_store.go:309)。
  • 每次编辑保存生成新 document_snapshots,指向新的 content_sha256;未变化的正文块复用同一 blob 行。→ 编辑保存不会复制未改动内容,写入时才产生新 blob。→ 满足「可编辑文档 CoW」。

结论

  • 去重:物理层早已实现(sha256 + ref_count);本次补齐的是逻辑提示——把 FileReference.IsDeduplicated 透出到上传/列表 API 的 deduplicated 字段,并在前端附件卡片与文档预览面板展示「重复·已复用」,让"只存一份"对用户可见。跨项目/同项目的逻辑引用记录保留(权限与审计需要),不做合并(已与用户确认方案:物理一份 + 提示)。
  • CoW:语义已是事实实现,但缺防回归守卫。本次新增 TestCAS_ImmutabilityCoWContract(cas_test.go)固化契约:① 相同内容重复写入 → 物理 blob 数不变、字节不变;② 内容变化写入 → 新 blob、旧 blob 不被覆写、历史引用仍读原始字节。未来任何"就地改写 blob"的实现都会在测试期失败。

严重度

low —— 现状正确,本次为可见性增强 + 契约固化,无缺陷修复。

关联整改

开放问题

  • storage_blobs.ref_count 目前只增不减;引用删除(若未来支持资产删除)需配套 decrement 与 blob 物理回收,属后续独立任务,不在本次范围。