Repository navigation
v5.7.0 — 简易网络同步
本页会随勘误就地更新。规范全文以
main为准。
这一版只回答一个问题
「好几个程序共用一个网盘目录,怎么写、怎么读,才不会把文件写坏?」
不实现任何传输协议、不绑定任何厂商——只守"文件别被写坏"这一层。
设计思想(守这三条)
- 我们只管纪律,不管传输:同步、加密、断点续传交给现成的网盘/服务器;
- 半截文件是最贵的错:宁可慢一点,也绝不让别的进程读到写了一半的东西;
- 删除不可逆,所以不删:删改一律移进
Archive\,宁可占空间。
步骤:写和读各一条线
写:分片(自己命名,不碰别人的)
→ 网盘可用?
├─ 是 → 写临时名 → rename 成正式名 → 持锁更新总索引
└─ 否 → 追加本地队列(不丢、不阻塞)
读:只读总索引 → 按需去取某一片(不扫全目录)
断网不是异常,是预期内的分支:写不进去就排队,恢复后补交,补交幂等。
要实现什么(目标 → 机制)
| 目标 | 靠什么机制做到 |
|---|---|
| 多个写者不打架 | 各写各的分片,从"抢锁"降级成"零竞争" |
| 观察者永不读到半截 | 先写 .tmp,rename 才是原子替换 |
| 总索引不被写坏 | 单写手 + 文件锁,拿不到锁宁可这次不写 |
| 网盘掉线不挂死 | 降级本地排队,--flush 幂等补交 |
| 误删可回滚 | 删改只移进 Archive\ |
细节(四条纪律 + 为什么)
- 分片写:每个进程写自己的名字(
节点__标题__时间戳),不去 append 别人在写的文件。 - 临时名 + 改名:改名是原子操作,观察者要么看到旧文件要么看到新文件;顺带绕开
"同步客户端在上传期锁住正式文件"的问题——被锁的只是临时名。 - 总索引单写手:聚合视图天生只能一个人改。取锁 → 读全部行 → 删同名旧行 → 追加 → 整体重写。
- 只移不删:删除不可逆,而多进程最常犯的错就是两边同时删。
证据
- 未配置网盘根 → 写入返回
QUEUED,本地队列 +1,进程不挂; - 配好后
--flush→ 队列全量补交、清空; - 3 个进程并发写 → 全部成功,0 个
.conflict、0 个残留.tmp; - 总索引持锁重写:无重复表头、按时间倒序。
边界(没做的)
- 真实网盘环境未验证(本机未配置
PERSONA_CLOUD); Archive\的 GC 独立线程未实现;- 跨时区节点的时间戳会乱序,接第二台机器时要改 UTC。
这只是我们自己的最小实现,仅供参考。 传输、加密、重试交给现成工具即可;
四条纪律可以直接学走,甚至一行代码都不用写。我们的宗旨是:只写最小实现和可能,从不强求别人怎么做。