☰
Kudu本地数据层原理:清理回执、删除日志与存储历史为什么用文件而不是数据库
2026/9/28 21:24:43 网站建设 项目流程

Kudu本地数据层原理:清理回执、删除日志与存储历史为什么用文件而不是数据库

【免费下载链接】kuduFree Windows, Mac and Linux cleaner, scanner, and more.项目地址: https://gitcode.com/gh_mirrors/kudu1/kudu

Kudu(免费开源的 Windows / macOS / Linux 系统清理与扫描工具)的本地数据层并没有依赖数据库,而是用 JSON、JSONL 与原子文件操作实现清理回执、删除日志和存储历史三大存储,better-sqlite3 则只用于优化用户的 SQLite 数据库文件。本文带你快速看懂这套设计。

先澄清一个常见误解:better-sqlite3 存什么、不存什么

很多读者以为 Kudu 的所有记录都存在 SQLite 里,实际并非如此:

  • 清理回执(Cleanup Receipts)、删除日志(Deletion Log)、存储历史(Storage History)都以普通文件形式存放在用户数据目录(userData)下;
  • better-sqlite3 是 Kudu 的运行时依赖,但它只服务于数据库优化器:对用户应用遗留的 SQLite 文件执行VACUUM压缩,而不是存放 Kudu 自身的记录。

这个选择很务实:清理工具的数据写入频率低、单条记录小,且需要跨进程(GUI、守护进程、CLI 共用同一数据目录)安全共享,文件 + 原子重命名 + 文件锁就足够可靠,还便于人工查看与排查。

三大本地数据存储一览

数据位置(userData 下)格式关键机制
清理回执cleanup-receipts/receipts.json索引 + 单回执 JSON跨进程文件锁 + 写队列
删除日志deleted-files.jsonlJSONL 追加写8 MB 滚动轮转
存储历史storage-history/index.json索引 + 快照 JSON完整性校验 + 损坏隔离
数据库优化目标 SQLite 文件-better-sqlite3 子进程 VACUUM

清理回执:一次清理的“收据”

回执记录了每次清理删了什么、为什么有的文件没删掉。核心实现在 cleanup-receipts.ts,几个值得学习的细节:

  • 跨进程文件锁:打包版 GUI、后台守护进程和--cli模式各自有独立的内存写队列,共享同一数据目录。代码用一个receipts.lock文件互斥,锁里写入持有者的随机 token(只释放自己的锁),30 秒未刷新的“僵尸锁”可被原子重命名方式安全回收,运行中每 10 秒心跳续期,慢任务不会被误判为崩溃;
  • 失败原因只存原因码:例如permission-denied、in-use、recently-modified(见 cleanup-receipts.ts 中的REASON_CODES),而不是原始异常信息,避免把含隐私的绝对路径写进日志;
  • 同进程串行写队列:所有索引更新排进同一条 Promise 链,配合“写临时文件 + 原子 rename”落盘,任何时刻磁盘上都是完整数据。

回执的展示逻辑在 cleanup-receipts.ipc.ts,共享类型定义在 cleanup-receipts.ts。

删除日志:六位数文件量级下的追加写设计

删除日志的目标是:任何一次清理都能事后审计。实现见 deletion-log-store.ts,设计非常克制:

  • JSONL 而非 JSON:一次深度清理可能删除几十万甚至上百万个文件,每批删除追加一行,内存与写开销保持恒定;
  • 8 MB 滚动轮转:超限后重命名为deleted-files.old.jsonl,空间占用有上限;
  • 按需读取:启动时不加载任何日志,查询时才读取,默认返回 200 条、上限 1000 条;
  • 最佳努力(best-effort):写日志失败绝不让清理本身失败——记录系统可以为审计服务,但不能拖累主流程。

存储历史:带完整性校验的磁盘快照

存储历史保存每次磁盘扫描的快照,支撑容量趋势图与增长告警,实现在 storage-history-store.ts:

  • 索引 + 明细两级结构:index.json只存摘要(最多 10 个作用域、900 条快照),每个快照的完整数据单独存为 UUID 命名的 JSON 文件;
  • 防篡改校验:快照携带 64 位十六进制校验和,索引加载时逐字段验证类型、范围与格式;
  • 损坏自愈:索引解析失败时整体隔离为index.corrupt-<时间戳>并重新建空索引,一次损坏不会导致功能永久不可用;
  • 孤儿文件清理:每次变更前顺带删除未被索引引用的旧明细文件,磁盘不膨胀。

better-sqlite3 的真正岗位:数据库优化器

Kudu 能扫描出用户系统里散落的 SQLite 文件(浏览器、应用缓存等)并压缩它们,这一步才用到了 better-sqlite3:

  • database-vacuum.ts 中打开数据库设置了timeout: 250——忙库直接跳过,不去反复争抢正在使用它的应用的写锁;随后执行VACUUM,并统计主文件与-wal文件的大小差作为“回收空间”;
  • 由于 better-sqlite3 是同步 API,卡死的原生命令无法用 Promise 超时打断,Kudu 把它放进独立子进程 database-worker.ts 运行,父进程可通过 database-optimizer.ts 设置 30 秒总时限并直接杀掉卡死进程;
  • 打包后的可用性由 package-smoke-test.js 冒烟测试兜底,确保 better-sqlite3 原生模块随安装包正确构建。

小结

  • 用文件而非数据库承载回执、日志、历史,换来跨进程简单互斥、人工可查、零外部依赖;
  • 三条通用防线贯穿所有存储:原子 rename 落盘、文件锁/写队列串行化、损坏时隔离自愈;
  • better-sqlite3 以“子进程 + 短超时 + 总时限”的方式被安全地用在数据库优化器上,做到优化别人的库时绝不影响 Kudu 自身。

想深入了解完整实现,可以获取源码后从 src/main/services/ 目录读起:

git clone https://gitcode.com/gh_mirrors/kudu1/kudu

【免费下载链接】kuduFree Windows, Mac and Linux cleaner, scanner, and more.项目地址: https://gitcode.com/gh_mirrors/kudu1/kudu

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询