# btrfs-space **Repository Path**: snyh/btrfs-space ## Basic Information - **Project Name**: btrfs-space - **Description**: btrfs space - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-23 - **Last Updated**: 2026-10-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Btrfs Space 懒猫微服的只读存储空间分析 LPK,应用 ID 为 `cloud.lazycat.app.btrfs-space`。无需 quota,不遍历文件;以 Btrfs 子卷 ID 和数据分配的完整引用集合为统计基础,默认按用户、应用、快照分组。 ## 页面与统计口径 - 已使用总量来自 statfs,与 df 使用相同口径。分类图按已分配样本占比缩放到 Btrfs SPACE_INFO.DataUsed,依次归入用户、应用、快照及其他。共享块优先归用户,其次应用;与系统数据共享且没有用户/应用引用时归其他。仅全部引用都属于快照的块归快照,因此快照部分对应删除全部快照可释放的数据。原始共享统计和组合回收算法保持不变。 - 比例条逐用户、逐应用显示名称,点击查看名称、ID、占用和比例;快照合为一项,点击查看关联的用户与应用,图注保持分类汇总。同类不同用户/应用共同引用的块平均分摊,同一用户/应用的多个子卷不增加分配权重。误差显示在暂停/继续采样按钮上。 - 引用空间按子卷或分组去重;同一子卷内的 reflink 和硬链接不会重复计算。跨项共享空间会出现在各项引用中,不能逐项相加。 - 组合回收要求一个数据分配的全部引用子卷都属于所选集合,每个分配只计一次。实际删除后的即时 df 变化还受到元数据、delayed refs 和后续写入影响。 - 文件、子卷、分组和组合回收估算使用逻辑数据字节,不重复计入 RAID1 镜像副本,也不计入 RAID5 校验条带;因此不代表包含 RAID 冗余的物理占用或实际删除后的即时回收量。顶部总量仍来自 statfs/df,分类仍按 SPACE_INFO.DataUsed 缩放,差额归入其他,不自行推算 RAID 物理开销。不同受支持 data profile 共存时按各 chunk 的逻辑长度统计。 - 顶部默认没有置顶区域;勾选后出现一行固定的预计可释放空间,取消选择后整行隐藏。采样次数、用时、采样IO消耗及暂停/继续按钮位于已使用空间卡片内,明确说明分类和排行为统计学采样估算、非精确数据。 - 只展示 /document 子卷的文件排行,位于子卷区域之前,默认 Top 10。标题旁默认收起的设置入口可调整排行项数。 - 用户、应用、快照和展开的子卷中,已有采样结果且引用空间为 0 的条目不显示。共享数据存在、可回收为 0 的条目保留。未开始采样时不以零值判为空。 - 子卷区域没有内部纵向滚动条,随整个页面滚动。应用名称和图标从只读挂载的 package.yml 和 icon.png 读取。用户名来自文稿子卷的登录账号名。 ## 采样与自动暂停 在 DATA/SINGLE、DATA/RAID0、DATA/RAID1 或 DATA/RAID5 chunk 的总逻辑字节域内均匀抽样,每批生成 128 个随机地址,排序查询以改善局部访问,整批完成后打乱发布。使用 LOGICAL_INO_V2 / IGNORE_OFFSET 获取完整 inode/root 引用,保留地址、时间、唯一 root 集合和 inode/path 信息。接口报告引用列表不完整时扩大接收缓冲区完成读取,仍不完整或查询失败时停止并报告错误。 每个新样本通过 inode-ref、inode-extref 和父目录元数据解析路径,不读取文件内容。并发删除导致的 ENOENT 保留为失效路径引用,其余查询错误终止采样。路径聚合按每个采样点对同一路径至多一次处理;目录之间、父子目录及共享文件的结果仍不可相加。 分类估算使用单项近似 99% Wilson 模型区间,以已分配样本为分母并缩放到 DataUsed。五个分类中最大的单侧区间距离不超过 df 已使用空间的 1% 时自动暂停。99% 是单项、静态独立抽样模型下的置信水平,不是整个页面的准确率,也不是连续监测停止时的严格 99% 覆盖保证;区间不包含写入、删除和快照造成的漂移。 达标自动暂停后,页面心跳和后台调度不会自动恢复。显式继续允许在已达标的状态下继续更新估算,直到用户手动暂停;未达标时恢复正常的达标自动暂停模式。暂停及继续状态保存在缓存中。移除按秒数和点数设置限额的界面与接口。重新计算按钮在批次边界清空采样池、排行索引及本轮次数/用时/IO计数,刷新文件系统库存后自动采样到误差达标;保留用户文件和子卷。 页面可见时持续采样,后台每 10 分钟执行 3 秒采样,暂停时均不运行。最多保留 100,000 点,满后轮换旧点;区间只使用保留样本,累计查询次数不作为样本量。原始 gzip JSON 缓存正常保存,旧版中的限额字段被忽略,已有样本继续读取。FSID 或数据 chunk 域变化会使旧样本池失效。 读取量是固定采样 OS 线程执行 Btrfs 查询期间的 read_bytes 增量;HTTP、图标及缓存 I/O 不计入。它不是整盘 I/O,也不是内核提供的通用 PID × 设备统计。 ## 构建与权限 ```sh go test -race ./... GOCACHE=/tmp/lzc-space-go-cache lzc-cli project release . -o cloud.lazycat.app.btrfs-space-v0.3.0.lpk ``` Go 使用 yaml.v3 解析应用名称,前端没有第三方依赖。默认 Linux amd64,`SPACE_ARCH=arm64 sh ./build.sh` 支持 arm64。compose override 给应用 SYS_ADMIN,并只读挂载 `/data/system/pkgm/apps` 到 `/lzcapp/host-apps`。通过 `/lzcapp/var` 的 Btrfs fd 查询数据盘,不挂载用户文件目录。仅管理员可访问;支持 DATA/SINGLE、DATA/RAID0、DATA/RAID1 和 DATA/RAID5,其他 data profile 和 mixed 数据/元数据布局仍报告不支持;元数据计入 df 的其他部分。逻辑地址查询由内核处理条带、镜像与校验布局,应用不自行映射设备地址。 主要接口:`GET /api/state` 返回原始子卷、展示分组和模型误差状态;`POST /api/state` 传入选中 root IDs 获取组合回收估算。`POST /api/activity` 维持页面活动,`POST /api/pause` 暂停,`POST /api/resume` 显式继续。`POST /api/recalculate` 请求重新计算,返回 202,在批次边界执行重置。`GET /api/top?m=4&n=10` 返回统一 rows,并保留 directories/files 字段。所有控制 POST 需要 X-Space-Request: 1 并检查同源。应用不提供删除数据接口。 ## 验证 核心纯算法测试覆盖 reflink 去重、组合回收包含关系、样本轮换、区间边界、分组规则、路径聚合、父子链合并及自动暂停/手动继续。data profile 回归覆盖 SINGLE、RAID0、RAID1、RAID5 的 chunk 解析、profile 共存、逻辑采样域、不重复计入冗余、缓存读取及不支持布局的明确错误。 可选内核集成测试(默认跳过)通过 `BTRFS_TEST_FILESYSTEM=/测试挂载点 BTRFS_TEST_PROFILE=raid5 go test ./internal/sampling -run '^TestLiveDataProfile$' -v -count=1` 运行,需要 SYS_ADMIN 查询权限。请仅指向预先准备的独立测试文件系统:纯 `single`、`raid0`、`raid1` 或 `raid5` data profile,至少两个子卷,并在 `/document/` 中放置足够占比的数据以命中抽样(建议至少 32 MiB 随机内容,额外创建 reflink 和快照可验证共享引用)。测试只读查询,不创建、格式化或删除数据;检查库存、SPACE_INFO 逻辑计数、2,048 点实际采样、组合回收和文稿排行。真实 Btrfs 核心 AC 文档仍为 draft;算法测试不替代内核集成验证。 已部署 snyht13.heiyu.space 与 linakesi.heiyu.space。linakesi 的真实数据识别 1,087 个子卷、123 个分组;隐藏零数据条目后显示 19 组,保留共享数据但回收为 0 的项目。父子链修复验证使用同一批 40,576 点,四层链仅保留 scopes,估算值不变。已通过桌面和 390px/320px 手机视口、设置展开、分组选择与缓存读取验证。 snyh.heiyu.space 的真实数据盘为 Data/RAID0、Metadata/RAID1;btrfs filesystem usage 报告 Data ratio 1.00。采样使用内核逻辑地址反查,不自行定位磁盘条带,允许该非镜像的数据布局。 本轮最终真实验证:linakesi 从重新计算开始,18,688 个点时自动暂停,最大分类区间误差约 6.94 GiB,目标约 6.96 GiB;手动继续至少再采 128 点后可手动暂停。验证了仅文稿 Top 10、设置折叠、子卷无内部滚动、单行条件回收栏和 390px/320px 布局,页面无脚本异常。snyht13 在 6,912 点时达到目标自动暂停。snyh 的 RAID0 数据盘已完成实际采样并无错误。三台分别识别约 1,089、116、649 个子卷。 ## 自动构建与版本 依赖 Go(版本见 go.mod)及支持 `LZC_VERSION` 的 lzc-cli。 本地执行 `go test ./...` 验证,再执行 `./scripts/build-lpk.sh 0.3.1`, 产物保存为 `btrfs-space.lpk`;版本写入包内 package.yml,不修改源码元数据。 `.cation.yml` 定义相同验证和构建入口。默认分支提交通过后生成 Daily Build, 版本标签通过后生成 Release;平台通过 `CATION_BUILD_VERSION` 传入版本。 仅打包,不自动安装或发布商店。Daily Build 默认保留 15 天、预发布 30 天、正式版本永久保留。 隔离环境统一入口为 `./scripts/ci.sh ac` 和 `./scripts/ci.sh build 0.3.1`。 仅需 Docker 与 Dagger 1.0.0-beta.16,镜像中的 Go、Node 和 lzc-cli 版本由 `ci/Dockerfile` 固定。 平台调用此入口,普通开发者也可以直接复用;首次运行需要下载依赖镜像和 npm 包。 ## 独立预览 `python3 scripts/preview.py start --filesystem /待观察的目录` 从当前代码构建独立容器。 需要 Python 3、Go、Docker,以及位于 Btrfs 上的目录;容器使用 `SYS_ADMIN` 执行 Btrfs 只读查询, 文件系统目录只读挂载,采样状态写入独立 `.work/preview`,不会修改已安装应用。 未通过 cation 执行时,先提交工作区修改以固定预览代码版本。 启动后 `preview.json` 给出本机访问地址;使用 `status` 查询,使用 `stop` 停止并删除本次容器和镜像。 脚本失败保留实例记录,先查看 `docker logs ` 和实际状态,再显式查询或停止,不自动重启。 `.cation.yml` 的 preview 使用同一入口,平台提供工作区 tree 和生命周期身份校验。