📌 重点功能 · 同步 & 备份 MN 4.3 引入新架构

MN 4.3+ 起
给笔记装一套像样的数据架构

MN 4.3 起,MarginNote 在底层重做了一套数据存储——内容寻址对象池 + Manifest。把 git 那套"按版本提交、按 hash 寻址"的方式用在你的学习数据上。本地完整性、备份、跨设备同步都是它的应用面。"脑图乱掉""手写丢失"这些过去用户反复诟病的问题——在这套架构下被结构性解决,因为原子单元从 record 升到了 manifest。

01 · 架构是底座,应用是表层
一套版本化数据底层(SHA-256 + manifest + atomic write)+ 三类应用:本地完整性备份跨设备同步。底座一份,复用三处。
02 · 旧问题的根本解
旧 CloudKit 同步是 record 级——一个学习集会被 CloudKit 拆成多批,部分失败时布局元数据和节点位置可能错位。新架构是 manifest 级,一份学习集要么全成、要么全失败。
03 · 三层防护
即便不开同步:自动备份 在本地按 5 分钟 idle 出快照;同步前 / 冲突前 自动出快照;完整导出给你随时可保管的整库包。每层独立,互为兜底。

MN 3.x → 4.2:CloudKit 同步(record 级)+ 完整导出 MN 4.3+新一代数据架构 · 自动备份 · 本地完整性 Coming Soon:云盘同步

MarginNote 数据架构与三类应用 本地数据 → 数据架构(BackupStorage 内容寻址对象池 + Manifest 版本化)→ 三类应用:本地完整性 / 自动备份 / 云盘同步(Coming Soon)。Full Export 与 CloudKit 同步是兼容保留的旧机制。 本地 MarginNote 数据 学习集 · 卡片 · 摘录 · 脑图 · 手写图层 · 复习 · 文档 MN 4.3+ 全新 数据架构 · BackupStorage + Manifest 把 git 的版本管理方式用在学习数据上 内容寻址对象池 SHA-256 + atomic write Manifest 版本化 versionNumber + deviceId SQLite 事务 快照元数据原子提交 应 用 三 处 应用 ① 本地完整性 默认开启 5 分钟 idle 自动出快照 同步前 / 冲突前 自动出快照 应用 ② 自动备份 默认可开 按频率自动跑 · 增量 · 版本化 4 个目的地后端 应用 ③ 云盘同步 COMING SOON manifest 级跨设备同步 3 个云盘后端 → 崩溃 / 写错可恢复 不开同步、不开外部备份也保护 → 任意历史版本可恢复 本地 · WebDAV · 百度 · Google → 多端一致(snapshot 级) iCloud Drive · 百度 · Google 兼 容 保 留 · LEGACY 完整导出(Full Export) 手动整库一次性打包,独立于新架构 .marginbackupall · 三种粒度 迁移 / 长期归档场景仍是首选 CloudKit 同步 老牌 record 级同步(自 2015 起) CloudKit 私有库 · 同 Apple ID 设备 ↔ 与"云盘同步"互斥 · 设置里二选一 蓝 = MN 4.3+ 新架构 黄 = MN 4.2 及之前的兼容保留 虚线 = Coming Soon

中心是数据架构本身(MN 4.3 引入),它在三处被复用:本地完整性安全网 / 自动备份 / 云盘同步(Coming Soon)。下方完整导出CloudKit 同步是 MN 4.2 及之前就存在的旧机制,与新架构并存。

全新 · MN 4.3 起
git 那套版本管理方式,
用在你的学习数据上。

从 MN 4.3 起,MN 引入了一套版本化数据底层——不只是"备份"或"同步",而是被三处复用的底座。这是 MN 这一代的架构升级。

01

对象池

内容寻址 SHA-256

每条数据按 SHA-256 hash 寻址存储——相同内容只存一份。文件用 writeToFile:atomically:YES;索引插入失败时删除刚写入文件回滚

  • Loose 对象 + Pack 文件(>1000 / >50MB 触发打包)
  • 对象损坏可重建索引
02

Manifest

snapshot 级原子单元

每个学习集快照是一个 Manifest,记录 versionNumber + deviceId + 内容 hash + 依赖关系。同步和恢复以 manifest 为单位,不再是字段或 record 级。

  • 这是新架构的核心——一份学习集要么全成、要么全失败
03

SQLite 事务

元数据原子提交

快照元数据写入用 SQLite transaction。要么这次快照完整入库,要么没出现——不会留下半成品 manifest

  • BackupSnapshots_v4.sqlite(schema v6)

⚠ 这套架构不是 CoreData + 对象池 + 快照 DB 的全局单事务——是"对象池写原子 + manifest 写原子"两件事各自原子。整体体验是版本库式安全网,不是数据库级 ACID 日志。

MN 4.3+ 新增
不开同步、不开外部备份——
架构本身就在保护你的数据

"丢手写""脑图乱掉""崩溃后笔记不见"是 MN 用户长期反馈的几大痛点。新架构在本地就以快照形式承接编辑——不需要你为它配置任何远程目的地。

默认行为

5 分钟 idle 出快照

每次编辑学习集 → 标记 dirty → 编辑停下 5 分钟 → 系统在本地版本库出一份不可变快照。

  • 同步前自动出快照(默认开)
  • 冲突前自动出快照(默认开)
  • 同步后自动出快照(默认,避免重复)
崩溃恢复

对象 + 索引可重建

对象内容 hash 校验失败时——比如硬盘扇区坏 / 文件损坏——可以触发 verifyIntegrity + rebuildIndex 重建对象索引。

  • UI 入口:修复缺失基线版本(推荐),仅在检测到未覆盖学习集时显示

诚实边界:上面这套保护建立在自动快照默认开启的前提上。如果你手动关掉自动快照、且没有跑过任何手动 / 基线快照,那么"崩溃前一秒的状态"代码侧没有保证能恢复。架构提供的是最近一份完整快照之内的回溯能力,不是逐键不可丢失。

LEGACY · 2015 起
CloudKit 同步:record 级、Apple iCloud 私有库、历史包袱较重

自 2015 年起的老牌同步系统。基于 CloudKit 私有库,同 Apple ID 的多设备实时一致。是 MN 多年来的主流同步——但它在结构上有一个根本性缺陷,下面这块说清楚。

同步范围

学习集(Topic)/ 摘录与笔记(BookNote)/ 媒体附件 / 文档配置 / 复习进度(FSRS)/ 标签 / 高亮样式

单个 PDF 大于 256 MB 时不上传 iCloud Documents——避免 iCloud 长时间卡住。

触发机制

变更追踪:学习集编辑 → 标记 dirty → 后台增量同步

实时拉取:CloudKit zone subscription 监听远端变更,远端更新即拉取

冲突处理(record 级)

CloudKit 乐观锁(CKRecordSaveIfServerRecordUnchanged)+ 基于 hash / 时间戳 / dirty 的字段级合并。不在 StudySet 维度上提供整体一致性——这是下面"乱掉"问题的根源。

失败回退

token 过期 → 自动重拉;CloudKit 部分失败 → 按 record 分别处理;无解时:重置 iCloud 同步缓冲 强制全量重同步。

为什么会"乱掉"

原子单元是 record,不是 StudySet

CloudKit 同步的最小单位是 CKRecord。每个 Topic(学习集)和 BookNote(笔记)都是单独的 record。"脑图乱掉"这种历史报障的技术根源是:

  • 布局元数据Topic.optionsJson)和节点位置BookNote.mindpos分布在不同 record
  • CKModifyRecordsOperation.atomic = YES 只覆盖当前批次。一个 StudySet 因 resultsLimit / 媒体大小被 CloudKit 拆成多批上传
  • 批次 A 上传成功(含 Topic.optionsJson)但批次 B 失败(含部分 BookNote.mindpos)→ 远端布局指向不存在的节点位置 → 用户感受到"脑图乱掉"

这不是某次失误,是 record 级同步的结构性后果。新架构(云盘同步)通过把原子单元升到 manifest 解决——见下文。

📌 设置入口:设置 → 云同步 → 笔记数据库同步模式 → CloudKit 同步。需要登录 iCloud。

两条备份路径:完整导出(旧)+ 自动备份(4.3 新)。

两条路径相互独立,可同时启用——也建议同时启用。完整导出是 MN 长期就有的旧机制(手动整库打包);自动备份是 MN 4.3 起新数据架构在备份场景上的应用(后台增量版本化)。

完整导出(Full Export) LEGACY

手动 · 整库一次性 · 长期就有

设置 → 备份与恢复 → 完整导出,三种粒度:

  • 导出内容(数据库 + 全部文档 + 历史版本)—— 全量打包,迁移到新设备首选
  • 导出内容(数据库 + 学习集文档)—— 只带与学习集关联的 PDF,节省体积
  • 仅导出数据库—— 只导出笔记元数据,不含 PDF

输出:MarginNoteBackup(yyyy-MM-dd-HH-mm-ss).marginbackupall

用户负责保管包文件——存哪由你决定。系统不强制上传任何云端。

自动备份(Auto Backup) MN 4.3+

后台 · 新架构应用 · MN 4.3 起

新数据架构(对象池 + Manifest)用在备份场景上——按你设的频率自动跑,只保存变化的部分

  • 备份频率:仅手动 / 每小时 / 每 6 小时 / 每 12 小时 / 每天 / 每周
  • 备份位置(4 选):本地文件夹 · WebDAV Server · 百度网盘 · Google Drive
  • 包含原始文档(PDF/视频):可选——带文档体积更大但恢复更完整

因为是新架构应用,对象去重 + 跨快照内容寻址自动获得。相同内容只存一份;半失败表现为缺对象(可修复),不是字段混杂。

默认:编辑 5 分钟 idle 自动出快照;同步前自动出快照;冲突前自动出预合并快照。

📌 设置入口:设置 → 备份与恢复。两条备份相互独立,建议同时启用。

MarginNote iPad 设置页 · 备份与恢复面板:完整导出(三种粒度)+ 自动备份(WebDAV / 本地 / 百度网盘 / Google Drive 四选)+ WebDAV 配置(服务器 URL / 用户名 / 密码 / 测试连接)
设置 → 备份与恢复 的真实界面(iPad)。完整导出三种粒度 + 自动备份四个目的地(本地 / WebDAV / 百度 / Google)在这一屏都能找到。
COMING SOON MN 4.3+ 架构应用

云盘同步:把"对象池 + Manifest"用在跨设备同步上。

下一代同步系统——和 CloudKit 同步是互斥关系(设置里二选一)。它不是"另一种 CloudKit",而是用 MN 4.3 起的新数据架构把同步重做一遍。原子单元从 record 升到 manifest,"脑图乱掉"那种结构性问题在新架构下不再发生。

支持的云盘后端(3 个)

iCloud Drive · 百度网盘 · Google Drive

代码里为 OneDrive / Dropbox 预留接口(暂时隐藏),WebDAV 仅备份支持,不在云盘同步选项中。

同步原子单元 = Manifest

每次变更生成不可变快照versionNumber + deviceId + 内容 hash 都在 manifest 里。

关键差异:远端文件传输仍可能半失败,但表现为缺对象或索引损坏(可修复),不会出现"布局指向不存在节点"的字段混杂

冲突处理(用户决策)

检测到版本冲突时 UI 弹三选:使用远程 / 合并(默认)/ 保留本地

合并前自动创建 Pre-merge 备份——即便合并选错,原始数据还在。

跨设备恢复

新机首次开 App 时拉取远端快照,按 manifest 重建本地数据;可选下载原始文档(PDF/视频)。

对象损坏时可重建索引,远端缺对象时可触发 baseline repair。

📌 当前状态:代码已完成,UI 由内部开关 mn5SyncSupported 门控;具体放出时间另行公告。

同样的"同步失败"——
旧架构会乱掉,新架构会缺对象

这两种失败的恢复成本完全不同:"乱掉"需要用户人工辨认哪份数据是错的、可能要回滚或手工修复;"缺对象"是可见的、可定位的、可自动修复的——它告诉你哪个 hash 没下载完,重新拉一次就好。这就是 MN 4.3 引入新数据架构带来的差别。

维度 MN 4.2 之前(CKRecord 级) MN 4.3+(Manifest 级)
写入原子性 CoreData 保存层面有原子性,但同步层以 Topic / BookNote CKRecord 为单位 对象用 writeToFile:atomically:YES;索引插入失败回滚刚写文件;快照元数据用 SQLite 事务
同步原子性
(一个学习集的所有变更)
CKModifyRecordsOperation.atomic = YES 只覆盖当前批次,一个 StudySet 因 resultsLimit / 媒体大小被拆成多批 manifest 为可见单元;远端传输可能半失败,但半失败 = 缺对象(可修复),不是字段混杂
冲突可见单元 record / 字段级,依赖 CloudKit save policy 和 changedKeys snapshot / manifest 级,用 versionNumber + deviceId + manifest hash 提交
半失败状态 CKErrorPartialFailure → 维护 failed/missed records,可能用 atomic = NO 清理引用错误。用户感受:脑图乱掉 对象池可能缺对象或索引损坏,但有 verifyIntegrity + rebuildIndex用户感受:提示需要重新同步对象
回滚能力 没有 StudySet 级 immutable manifest 可回滚;依赖旧备份 / 手动冲突处理 可恢复到任意历史快照;baseline repair 补齐缺失版本覆盖
内容 hash 校验 只用 hashOfDataCRC 做差异判断,不是整 StudySet manifest 的内容寻址提交 对象和 manifest 全部 SHA-256 内容寻址
跨设备一致性保证 CloudKit record 级乐观锁;StudySet 全量一致性需跨多 record / 多批次拼出来 manifest / snapshot 级"版本提交"——但仍不是 CRDT,不是实时协同

网络断 / 冲突 / 配额满 / 跨账号——都有兜底

同步备份系统的真实价值不在它正常工作时,而在它出问题时。这一节讲清楚每种失败模式的恢复路径——你应该知道当 things go wrong 时按哪个按钮。

同步状态栏

正在检查更新 / 准备下载 / 下载中(n/m)/ 准备上传 / 上传中(n/m)/ 同步完成 / 同步失败

每个状态对应实际的同步阶段——没在猜,在算。

冲突 UI(云盘同步)

检测到版本变更时弹三选:使用远程 / 合并 / 保留本地。默认选"合并",合并前自动出 pre-merge 备份。

重置同步缓冲

CloudKit 同步出现卡顿或异常时,可在 设置 → 云同步 重置同步缓冲——所有数据会重新比对。是核选项,按钮有二次确认。

手动同步备份

每次手动触发同步前会自动备份本地数据库到 Documents/ManualSyncBackups保留最近 5 份。冲突再严重,最近 5 次手动同步前的状态都还在。

管理 CloudKit 区域

用过 CloudKit 同步后想清空云端可见数据,可在设置里手动删除 CloudKit zones——释放 iCloud 配额,不影响本地

对象池 GC + 基线修复

云盘同步的对象池可手动触发垃圾回收(GC)+ 基线版本修复——解决长期使用产生的孤儿对象与基线缺失问题。

有些事 MN 不承诺

"绝不丢数据"听起来好——但工程上没有任何系统能这么承诺。MN 选择不夸口,而是把每层兜底机制讲清楚。

不是实时协同(CRDT / OT)

同步是基于变更追踪的最终一致——多设备会在几秒到几分钟内对齐。不是 Google Docs 那种"两个人同时编一段、字符级合并"。MN 不做实时协同。

不是完整 Git 三方 merge

云盘同步的合并算法是 manifest / hash / 时间戳的对象级合并——比 last-write-wins 强,但目前没有完整共同祖先(common ancestor)查找。所以"git for study notes"是设计灵感比喻,不是字面对等于 git。

本地保护需要快照已生成

"架构本身保护数据"建立在自动快照默认开启的前提上。如果你手动关掉自动快照、且没跑过任何手动 / 基线快照,崩溃前一秒的状态代码侧没有保证能恢复。可恢复的是"最近一份完整快照"。

不承诺零数据丢失

云盘服务故障 / 设备彻底损坏 / Apple ID 异常 / 操作误删——都可能发生。新架构 + 自动备份 + 完整导出层层兜底降低风险,但不打"绝对安全"包票。建议定期完整导出 + 一份保留在你能控制的位置(外部 SSD / 自己的 NAS / 不同账号的云盘)。

关于版本:本页讲到的"新数据架构"自 MN 4.3 起引入。"云盘同步"是基于这套架构的下一步,目前 Coming Soon——具体放出时间以官方 release note 为准。

不只是好用——更要放心

下载 MarginNote 4,把你的笔记交给一个把"数据安全"当作明确的工程任务来做的工具。