news 2026/10/8 15:02:29

Mindwtr如何实现多端无损同步?完整拆解它的合并算法、墓碑机制与冲突解决策略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Mindwtr如何实现多端无损同步?完整拆解它的合并算法、墓碑机制与冲突解决策略

Mindwtr如何实现多端无损同步?完整拆解它的合并算法、墓碑机制与冲突解决策略

【免费下载链接】MindwtrGet tasks and ideas out of your head. A free GTD to-do app for desktop and mobile. Works offline, no account needed项目地址: https://gitcode.com/gh_mirrors/mi/Mindwtr

Mindwtr是一款免费、开源、本地优先的 GTD 待办事项应用(To-Do App),支持桌面端和移动端离线使用、无需注册账号。它最核心的能力之一,就是多端无损同步:你在手机上改的任务,打开电脑就能看到;而多台设备同时修改同一条任务时,Mindwtr 依靠一套版本感知的合并算法(revision-aware merge)、墓碑机制(Tombstone)和确定性的冲突解决规则,保证所有设备最终收敛到完全一致的结果,且不丢失任何一方的有效修改。

为什么简单的"最后写入 wins"不够用?

很多人的第一反应是:两台设备改了同一条任务,谁的时间戳晚就听谁的。但 Mindwtr 的架构决策记录(ADR)里明确指出,纯时间戳的 last-write-wins 有三个致命问题(见 docs/adr/0003-revision-aware-sync.md):

  1. 设备时钟会漂移:手机和电脑的时钟可能相差几秒甚至几分钟,"晚"不等于"新";
  2. 删除不能消失:A 设备删掉了任务,B 设备同时改了它,如果简单比较时间戳,删除可能被"复活",或者修改被静默吞掉;
  3. 时间戳完全相等时:仍然需要一个确定性的裁决规则,不能靠遍历顺序碰运气。

所以 Mindwtr 选择了版本元数据 + 时间戳 + 墓碑 + 确定性平局裁决的组合方案。

快照同步:没有增量日志的"轻量级"路线

在动手之前,先理解 Mindwtr 同步的整体形态:它做的是全量快照合并,而不是逐条操作日志(delta log)。这一点在 docs/adr/0008-snapshot-sync-without-delta-log.md 中被明确决策并保留了:

  • 个人 GTD 应用的实体数量小、设备数量少、数据属于个人而非团队协作;
  • 整个数据是一个 JSON 快照文件(本地持久化为 SQLite),全文件写入简单且原子;
  • 每条数据上自带的rev(版本号)和revBy(最后修改者)字段,已经足以防止"丢失更新",不需要额外的操作日志。

一次同步周期的流程非常直白:拉取远端快照 → 归一化 → 逐实体合并 → 写回一份合并结果,核心实现在 packages/core/src/sync.ts 与 packages/core/src/sync-cycle.ts 中。

这也解释了为什么 Mindwtr 支持 iCloud、WebDAV、文件同步甚至自建云等多种后端——它们只是快照的"搬运工",真正的合并逻辑只有一份(见 docs/adr/0010-self-hosted-cloud-sync-server.md),所有通道行为完全一致。

核心关键词①:版本感知的合并算法

Mindwtr 的合并策略按优先级依次比较,每一级都是确定性的:

优先级比较信号说明
1实体归一化合并前先把两侧数据清洗成可比较的形式(sync-normalization.ts)
2版本号rev/revBy谁的版本更新,谁赢——这是对抗时钟漂移的主力
3时间戳版本号不可比时,用操作时间排序
4删除 vs 存活(delete-vs-live)规则删除和修改撞车时的专门裁决,见下文
5确定性平局裁决内容签名 + 稳定排序,保证每台设备选出同一个赢家

第 5 步值得展开:当版本号和时间戳都无法区分时,packages/core/src/sync-signatures.ts 会对任务内容做哈希签名,再用确定性的平局规则(如字典序)选出赢家。确定性是这里的关键——不是"随便选一个",而是"任何设备、任何时刻、重复计算都选出同一个"。这就是"无损同步"的数学基础。

核心关键词②:墓碑(Tombstone)机制

删除是怎么跨设备传播的?答案是"软删除墓碑":删除一条任务时,Mindwtr 不真正抹掉它,而是给它盖上deletedAt时间戳,让它以"墓碑"的身份继续参与同步,把"这里曾经有个东西,被删了"这个事实通知到每台设备。

保留多久?规则在 docs/adr/0005-tombstone-retention-policy.md 中定义:

  • 墓碑默认保留90 天(可在 1 天到 3650 天之间调整),默认值见 packages/core/src/sync-tombstones.ts;
  • 保留窗口内,墓碑始终留在快照和同步载荷中——太早删掉,长期离线回来的设备可能把"已删除的任务"复活;
  • 过期后由显式的清理步骤(purgeExpiredTombstones)清除,而不是在普通读取时顺手删;
  • 被彻底清除(purged)的记录永不复活,恢复操作会把它视为不存在。

核心关键词③:冲突解决的演进——"存活数据优先"

删除 vs 修改是最棘手的冲突:A 设备删除了任务,B 设备几乎同一时刻修改了它,听谁的?

Mindwtr 这里走过一次演进,非常值得学习:

  • 早期规则(0.8.2 之前):操作时间相等时,墓碑优先——宁可错杀也不让删除消失(ADR 0003);
  • 实际流量暴露问题:在时钟漂移的设备上,这条规则太激进,容易把有效的修改连同任务一起删掉;
  • 现行规则(ADR 0007):在 docs/adr/0007-live-wins-in-ambiguous-delete-merge.md 中改为存活数据优先:
  1. 用操作时间(删除取max(updatedAt, deletedAt))比较两个操作;
  2. 两者相差超过 30 秒:较新的操作赢;
  3. 落在30 秒模糊窗口内:版本号(rev)高的一边赢;
  4. 仍无法区分:保留存活的任务,而不是让删除默认获胜。

这个设计体现了务实的工程哲学:在"可能丢一次删除"和"可能丢一次用户修改"之间,选择保住用户的修改——因为前者重新删一次就行,后者是真实的劳动成果。

这套机制对普通用户意味着什么?

  • 离线随便用:飞行模式下改了任务,联网后自动同步,合并结果在任何设备上都是同一个;
  • 多后端随意切换:iCloud、WebDAV、文件同步、自建云服务器共用同一套合并规则,切换后端不会改变冲突行为;
  • 删除可安全传播:删掉的任务会在所有设备上消失,而不会被某台离线设备"救活";
  • 数据量友好:快照模型 + 墓碑定期清理,让同步文件保持有界增长。

想更深入阅读,可以从这几份材料入手:

  • 同步决策记录总目录:docs/adr/README.md
  • 同步编排与周期串行化:docs/adr/0014-sync-orchestration-ports.md、docs/adr/0016-sync-cycle-serialization.md
  • 附件的同步模型:docs/adr/0011-attachment-sync-model.md
  • 合并设置逻辑:packages/core/src/sync-merge-settings.ts

小结

Mindwtr 的多端无损同步 =全量快照合并(简单、原子)×版本号优先的时间戳比较(抗时钟漂移)×墓碑软删除(删除可传播、可收敛)×确定性的平局裁决(所有设备算出同一个结果)。它没有引入复杂的 CRDT 或增量日志,而是用一套小而完备的规则,把个人待办应用最真实的同步场景做到了"每台设备都一样"。

【免费下载链接】MindwtrGet tasks and ideas out of your head. A free GTD to-do app for desktop and mobile. Works offline, no account needed项目地址: https://gitcode.com/gh_mirrors/mi/Mindwtr

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 15:00:34

LeetCode 160 相交链表:双指针解法与哈希集合详解

我最近在整理自己的每日一题笔记,正好写到相交链表这道经典题。它是LeetCode第160题,也是链表模块里面试出现频率极高的一个。原题有很多马甲,比如找两个单链表的交点、判断两条链表是否合并过,但内核都是同一件事:给定…

作者头像 李华
网站建设 2026/10/8 15:00:21

Python上位机开发实战:从串口通信到Modbus与可视化

一直想聊一聊 Python 在上位机开发里到底能走多远。不少人一听“上位机”这三个字,第一反应就是 C# WinForms/WPF,或者 LabVIEW、QT C;打开招聘软件看一眼,半导体设备、BMS 测试、视觉检测这些岗位,JD 上写的也基本都…

作者头像 李华
网站建设 2026/10/8 14:59:56

Python FastAPI + uniapp 构建单词学习激励系统实战

看到这个项目标题,我第一反应是:这不就是把“坚持背单词”这个反人性的事情,用技术手段包装成让人上瘾的系统吗?作为一个做过多个小程序和教育类产品的开发者,我深知单词学习类App的留存有多难做。纯粹给你一个单词列表…

作者头像 李华
网站建设 2026/10/8 14:59:12

Docker容器化部署Zabbix监控系统:架构、实操与排障实战

自己折腾 Zabbix 一年多,从裸机装到容器化部署,中间踩过的坑能写满一本流水账。这篇就聊聊我目前最常用的部署方式——用 Docker 搭 Zabbix,把整个架构、为什么这么选、具体怎么落地、常见问题怎么排查一次说清楚。Docker 搭建 Zabbix 最直观…

作者头像 李华
网站建设 2026/10/8 14:58:27

SpringBoot+Vue3+MyBatis-Plus构建社区医院管理系统实战指南

前阵子有人在我的技术交流群里问社区医院管理系统能不能用现成的开源项目改一改就上,我当时的回答是:能,但千万别高估了“改一改”这三个字的含金量。社区医院的管理系统和三甲医院的HIS系统完全是两个物种,前者要的是轻、快、便宜…

作者头像 李华
网站建设 2026/10/8 14:57:58

claude-mem:用SQLite给Claude Code装上本地外脑,根治跨会话失忆

用 Claude Code 用得越久,越容易在同一个地方被卡住:它什么都好,就是记不住昨天的事。你可以在一个会话里把某个模块的设计思路、命名约定、历史坑位讲得明明白白,但只要关掉终端,下一个会话里的它就是一个全新的 AI—…

作者头像 李华