ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Remotely Save 同步算法 V3 设计全解:五输入源决策表、删除检测与增量同步分支实现

Remotely Save 同步算法 V3 设计全解:五输入源决策表、删除检测与增量同步分支实现 数据同步【免费下载链接】remotely-saveSync notes between local and cloud with smart conflict: S3 (Amazon S3/Cloudflare R2/Backblaze B2/...), Dropbox, webdav (NextCloud/InfiniCLOUD/Synology/...), OneDrive, Google Drive (GDrive), Box, pCloud, Yandex Disk, Koofr, Azure Blob Storage.项目地址https://gitcode.com/gh_mirrors/re/remotely-save点击查看免费下载导读本文档深入剖析开源仓库remotely-saveObsidian 双向云同步插件中新一代同步算法 V3 的完整设计它通过引入本地上次成功同步历史这一第五输入源实现了真正的删除检测true deletion detection、可配置的删除保护、双向 / 增量推送 / 增量拉取等多方向同步并以一张张决策表decision table穷举本地与远端文件的所有状态组合。读完本文你将理解 V3 的五个输入源分别是什么、双向与增量模式的决策分支编号如 branch 09/10/22–39各自对应什么操作以及这些设计如何在仓库源码尤其是 pro/src/sync.ts中落地。V3 的设计背景与定位Sync Algorithm V3 设计文档起草于 2024-01-17Drafted on 20240117其定位是一个绝对更好的同步算法an absolutely better sync algorithm核心改进点在于两点更好地追踪删除Better for tracking deletionsV2 依赖本地删除/重命名历史与远端删除历史V3 则把上次成功同步时的状态固化为一个独立输入源从而能判断某侧文件消失到底是删除还是从未存在过更好地支持子分支Better for subbranching即决策树被拆分成更多细分分支以便在不同同步方向双向、仅推送、仅拉取、推送删除、拉取删除下给出差异化、更安全的动作。根据 docs/sync_algorithm/README.md 的目录结构V1、V2、V3 三个算法版本是逐代演进的关系V1 只有三个输入源本地文件、远端文件、本地删除/重命名历史V2 增加了远端删除历史成为四个输入源V3 则在 docs/sync_algorithm/v2/README.md 的基础上进一步加入上次成功同步历史形成五个输入源。算法来源与许可说明设计文档明确声明V3 本质上是对以下开源算法的组合改造且这四个上游项目均以 MIT License 发布因此不存在许可争议Algorithm V2本仓库自身的上一代算法syncrcloneJwink3101rsincConorWilliamsrclone 的 bisync 方案中的部分思想。在源码层面pro/src/sync.ts 的第 536–540 行注释也印证了这一点Heavy lifting. Basically follow the sync algorithm of https://github.com/Jwink3101/syncrclone同时指出Also deal with syncDirection which makes it more complicated——即 V3 相比 syncrclone 额外处理了同步方向维度这正是下述多张决策表的由来。五个输入源与运行阶段V3 拥有五个输入源编号输入源说明1local all files本地全部文件Obsidian 可直接通过其 API 提供2remote all files远端全部文件部分服务直接提供 API部分服务需要插件递归扫描目录3local previous succeeded sync history本地上次成功同步的历史记录4local deletions本地删除记录5remote deletions远端删除记录运行阶段分为两次初始化运行Init run一次性消费远端删除记录remote deletions把历史数据转换为本地上次成功同步历史local previous succeeded sync history。也就是说首次同步时旧算法遗留的远端删除历史被吸收进新算法的历史基准中之后不再依赖它。后续运行Later runs仅使用第 1、2、3 个输入源本地文件、远端文件、上次成功同步历史。这是 V3 与 V2 最关键的结构差异删除检测不再依赖删除历史这条易失、易被伪造的记录而是通过当前状态 vs 上次成功同步状态的差分来推断。在实现上prevSync上次成功同步历史以数据库记录的形式存储。从源码看pro/src/sync.ts 中通过getAllPrevSyncRecordsByVaultAndProfile/upsertPrevSyncRecordByVaultAndProfile/clearPrevSyncRecordByVaultAndProfile这些函数定义于 src/localdb.ts按vaultRandomID profileID维度读写每条路径的上次同步记录dispatchOperationToActualV3在每个决策分支执行完毕后都会同步更新或清除对应记录从而保证上次成功同步状态始终准确反映最新一次同步结果。决策表V3 的核心机制V3 的核心是一系列双向表bidirectional table设计文档将其描述为基于 syncrclone 与 rsinc 修改而来增量推送/增量拉取专用表又是在双向表基础上进一步修改。表中单元格的数字即代码中的决策分支编号decision branch??表示该组合在相应模式下不会出现或暂未定义分支。在阅读表格前需要明确行/列含义行 本地状态local unchanged本地未变、local modified本地已修改、local deleted本地已删除、local created本地新建列 远端状态remote unchanged远端未变、remote modified远端已修改、remote deleted远端已删除、remote created远端新建。双向同步Bidirectionallocal\remoteremote unchangedremote modifiedremote deletedremote createdlocal unchanged(02/21) do nothing(09) pull(07) delete local(??) conflictlocal modified(10) push(16/17/18/19/20) conflict(08) push(??) conflictlocal deleted(04) delete remote(05) pull(01) clean history(03) pulllocal created(??) conflict(??) conflict(06) push(11/12/13/14/15) conflict双向模式的代表性决策branch 02/21 do nothing本地与远端都未变或内容完全相同无需操作branch 09 pull本地未变但远端被修改说明远端发生了新修改拉取远端版本branch 07 delete local本地未变而远端被删除说明删除发生在远端同步删除本地branch 10 push本地已修改而远端未变推送本地版本branch 16/17/18/19/20 conflict两侧都发生了修改或两侧同时新建进入冲突处理——具体选哪个分支取决于冲突策略见下文冲突策略与分支细分branch 08 push本地已修改且远端被删除本地修改晚于远端删除以本地为准推送branch 04 delete remote本地已删除而远端未变删除远端branch 05 pull本地已删除但远端被修改远端修改晚于本地删除以远端为准拉取branch 01 clean history两侧都已删除只剩历史记录清理该条同步历史branch 03 pull本地已删除且远端新建说明远端重建了文件拉取branch 06 push本地新建而远端已删除推送本地新文件branch 11/12/13/14/15 conflict两侧同时新建进入冲突处理。增量仅推送Incremental pushlocal\remoteremote unchangedremote modifiedremote deletedremote createdlocal unchanged(02/21) do nothing(26) conflict push(32) conflict push(??) conflictlocal modified(10) push(25) conflict push(08) push(??) conflictlocal deleted(29) conflict do nothing(30) conflict do nothing(01) clean history(28) conflict do nothinglocal created(??) conflict(??) conflict(06) push(23) conflict push仅推送模式只允许把本地变更上传到远端凡涉及应拉取或应删除的动作一律改写为冲突语义branch 26 conflict push本地未变但远端被修改按理应拉取但仅推送模式下以本地为准强制推送branch 32 conflict push本地未变而远端被删除按理应删除本地但仅推送模式下以本地为准重新推送branch 25 conflict push两侧都修改仅推送模式下保留本地并推送branch 29/30 conflict do nothing本地已删除而远端未变/被修改按理应删除远端或拉取但仅推送模式下既不删除远端也不拉取什么都不做防止误删远端数据branch 28 conflict do nothing本地已删除而远端新建什么也不做branch 23 conflict push两侧同时新建仅推送模式下保留本地并推送。增量仅拉取Incremental pulllocal\remoteremote unchangedremote modifiedremote deletedremote createdlocal unchanged(02/21) do nothing(09) pull(33) conflict do nothing(??) conflictlocal modified(27) conflict pull(24) conflict pull(34) conflict do nothing(??) conflictlocal deleted(35) conflict pull(05) pull(01) clean history(03) pulllocal created(??) conflict(??) conflict(31) conflict do nothing(22) conflict pull仅拉取模式只允许把远端变更下载到本地branch 33 conflict do nothing本地未变而远端被删除按理应删除本地但仅拉取模式下不删除本地branch 27/24 conflict pull本地已修改而远端未变/已修改按理应推送或冲突处理仅拉取模式下强制以远端为准拉取branch 34 conflict do nothing本地已修改而远端被删除什么也不做branch 35 conflict pull本地已删除而远端未变按理应删除远端仅拉取模式下以远端为准拉取回来branch 31 conflict do nothing本地新建而远端被删除什么也不做branch 22 conflict pull两侧同时新建仅拉取模式下保留远端并拉取。增量推送删除Incremental push and deletediff decisionBranch: 38local\remoteremote unchangedremote modifiedremote deletedremote createdlocal unchanged(02/21) do nothing(26) conflict push(32) conflict push(??) conflictlocal modified(10) push(25) conflict push(08) push(??) conflictlocal deleted(38) delete remote(30) conflict do nothing(01) clean history(28) conflict do nothinglocal created(??) conflict(??) conflict(06) push(23) conflict push与仅推送相比唯一的差异是local deleted × remote unchanged从 branch 29conflict do nothing变为branch 38 delete remote推送删除模式允许把本地删除传播到远端。增量拉取删除Incremental pull and deletediff decisionBranch: 39local\remoteremote unchangedremote modifiedremote deletedremote createdlocal unchanged(02/21) do nothing(09) pull(39) delete local(??) conflictlocal modified(27) conflict pull(24) conflict pull(34) conflict do nothing(??) conflictlocal deleted(35) conflict pull(05) pull(01) clean history(03) pulllocal created(??) conflict(??) conflict(31) conflict do nothing(22) conflict pull与仅拉取相比唯一的差异是local unchanged × remote deleted从 branch 33conflict do nothing变为branch 39 delete local拉取删除模式允许把远端删除传播到本地。决策分支在源码中的落地设计文档中的数字分支与 pro/src/sync.ts 的getSyncPlanInplace函数一一对应。该函数对每个key依次考察local、remote、prevSync三方状态并按表格逻辑打上decisionBranch与decision如remote_is_modified_then_pull、local_is_created_then_push、conflict_modified_then_keep_local。以下是几个典型分支的源码对照branch 2 / 21equal / do nothing当local.mtimeCli remote.mtimeCli || local.mtimeCli remote.mtimeSvr且local.sizeEnc remote.sizeEnc时判定为完全相同见源码约第 776–787 行branch 9remote is modified then pulllocalEqualPrevSync !remoteEqualPrevSync时若同步方向非仅推送则拉取远端第 798–824 行branch 10local is modified then push!localEqualPrevSync remoteEqualPrevSync时若同步方向非仅拉取则推送本地第 825–851 行branch 26 / 27上述两种单侧修改情形在仅推送/仅拉取方向下被改写为冲突语义第 807–816 行与第 834–843 行branch 25 / 24两侧都修改且都存在prevSync时仅推送模式取 branch 25keep local仅拉取模式取 branch 24keep remote第 916–978 行branch 38 / 39见前述源码第 1028–1031 行incremental_push_and_delete_only下local_is_deleted_thus_also_delete_remote与第 1116–1130 行incremental_pull_and_delete_only下remote_is_deleted_thus_also_delete_localbranch 22 / 23两侧同时新建prevSync undefined时仅拉取取 branch 22keep remote仅推送取 branch 23keep local第 854–915 行。值得注意的源码细节decisionBranch编号在实现中还扩展到了 100 以上文件夹分支 101–140以及 301/302smart conflict 合并分支说明设计文档中的表格主要描绘文件决策文件夹与智能合并被编码在更高编号的分支里。冲突策略与分支细分双向表中冲突单元格标注的16/17/18/19/20两侧修改与11/12/13/14/15两侧新建正是冲突策略的分流点。从 src/baseTypes.ts 第 233–236 行可知冲突策略类型为export type ConflictActionType | keep_newer // 保留较新者 | keep_larger // 保留较大者 | smart_conflict; // 智能冲突Pro 功能源码中的映射关系第 856–956 行为keep_newer比较local.mtime与remote.mtime较新者胜出 → branch 11/12新建或 16/17修改keep_larger比较local.sizeEnc与remote.sizeEnc较大者胜出 → branch 13/14新建或 18/19修改smart_conflict尝试把两侧内容合并branch 301/302若不可合并则复制为两个文件对应 pro/src/conflictLogic.ts 中的mergeFile与tryDuplicateFile。同步方向与设置项双向 / 增量方向由设置项syncDirection控制其类型定义位于 src/baseTypes.ts 第 131–136 行export type SyncDirectionType | bidirectional | incremental_pull_only | incremental_push_only | incremental_pull_and_delete_only | incremental_push_and_delete_only;恰好对应设计文档中的五张决策表。此外与算法相关的设置还包括conflictAction冲突策略、skipSizeLargerThan忽略超过该尺寸的文件见 docs/sync_algorithm/sync_ignoring_large_files.md、protectModifyPercentage删除保护阈值、syncConfigDir/syncBookmarks/syncUnderscoreItems是否同步配置目录、书签、下划线开头的特殊项以及ignorePaths/onlyAllowPaths过滤列表。功能清单Must have 与 Nice to have设计文档将 V3 的目标功能分为两档必须实现Must have真正的删除检测true deletion detection删除保护deletion protection可阻塞带设置项开关从旧算法的事务迁移transaction from the old algorithm用户警告提示——新算法要求所有客户端全部升级到新版本文档特意标注deliberately corrupt the metadata file??即通过作废旧元数据文件的方式强制升级过滤器filters对应ignorePaths/onlyAllowPaths冲突警告conflict warning部分同步partial sync即按需同步部分文件。锦上添花Nice to have真实的时间与哈希true time and hash冲突重命名conflict rename即两边都保留并改名。上述清单与 docs/sync_algorithm/v3/intro.md 中的面向用户的功能核对表基本吻合如sync conflict: keep newer、keep larger已完成keep both and rename、show warning未完成deletion: true deletion status computation、meta data: no remote meta data any more、sync direction: incremental push only / pull only、deletion protection: warning based on the threshold均已完成。删除保护Deletion Protection的实现侧证警告基于阈值warning based on the threshold这一删除保护机制在源码中体现为protectModifyPercentage设置项并与mixedEntityMappings[/$meta]中记录的protectModifyPercentage、syncDirection、triggerSource等现场信息配合用于在大量删除发生前向用户发出警告。从 pro/src/sync.ts 第 1200–1225 行可以看到每次生成同步计划时都会写入一份/$meta元数据记录服务类型、并发度、是否加密、同步方向、冲突策略、删除保护阈值等这份元数据正是算法判断本次变更规模是否异常的依据之一。升级通知与用户确认新算法需要所有客户端更新的警告在插件端由 src/syncAlgoV3Notice.ts 中的SyncAlgoV3Modal弹窗实现。该弹窗要求用户同时勾选两个确认框后才允许继续手动备份确认syncalgov3_checkbox_manual_backup对应manualBackup字段所有设备已升级确认syncalgov3_checkbox_requiremultidevupdate对应requireUpdateAllDev字段。只有当两个复选框都被勾选时同意按钮才解除禁用。同意后调用saveAgreeToUseNewSyncAlgorithm()并把设置项agreeToUseSyncV3见 src/baseTypes.ts 第 174 行置为 true同时按用户设置触发自动同步、初始化同步或保存即同步若拒绝则插件直接unload()卸载。目录文件夹的同步规则V3 设计文档本身聚焦文件级决策表但仓库中 docs/sync_algorithm/v2/README.md 对目录处理的规则在 V3 中依然成立V3 源码 pro/src/sync.ts 第 575–767 行以key.endsWith(/)区分文件夹且文件夹不看 mtime/size只判断存在性分支编号 101–140。V2 文档给出的文件夹规则可视为 V3 目录语义的补充说明先生成所有文件的同步计划。只要有文件存在其所有父目录都应存在——本地缺则本地递归创建远端缺则远端递归创建一个目录可删除当且仅当它出现在远端删除历史中且它本身为空或其所有子目录都可删除。文档还给出了三个典型示例设备 1 删除某目录并同步 → 设备 2 新建同名目录并同步 → 该目录在设备 2 上再次被删除设备 1 删除某目录并同步 → 设备 2 新建同名目录并放入新文件后同步 → 由于存在新文件该目录在设备 2 上被保留设备 1 删除某目录并同步 → 设备 2 未触碰该目录 → 该目录及其未改动的子文件在设备 2 上被删除。这一目录可删除性判定在 V3 源码中由keptFolder集合实现任何被判定为应保留的文件夹都会把其父目录递归加入keptFolder最终确保不会因删除父目录而误删子内容见 pro/src/sync.ts 第 560、578–621 行。从 V2 到 V3 的演进要点对比 docs/sync_algorithm/v2/README.md 可以更清楚地看到 V3 的改进输入源从 4 个变为 5 个V2 的四源为本地文件、远端文件、本地删除/重命名历史、远端删除历史V3 用上次成功同步历史替代了对删除历史的持续依赖仅初始化运行时消费一次远端删除历史判定基准从最大时间戳变为差分状态V2 的核心理念是收集 mtime/删除时间四个时间戳并尊重最大时间戳及其对应操作V3 则通过local、remote、prevSync三者是否两两相等来推断谁被修改、谁被删除从而避免时间戳倒流导致误判同步方向成为一等公民V2 只有双向语义V3 增加了仅推送、仅拉取、推送删除、拉取删除四类方向并以独立决策表定义每类方向下冲突单元格的行为删除保护显式化通过protectModifyPercentage阈值与警告机制防止一侧清空/大规模删除被当作正常变更传播到另一侧元数据不再上云V3 的prevSync历史存于本地数据库远端不再存放同步元数据文件intro.md 中meta data: no remote meta data any more已勾选这也意味着加密模式下的同步无需在远端维护额外元数据。总结Sync Algorithm V3 是 Remotely Save 项目同步内核的一次系统性重构它把上次成功同步历史作为第五输入源用五张决策表穷举本地与远端的全部状态组合并通过decisionBranch编号1–39 覆盖文件决策101–140 覆盖文件夹决策301/302 覆盖智能合并把每种组合映射为可执行动作。双向、增量推送、增量拉取、推送删除、拉取删除五种方向各自拥有独立的冲突语义配合keep_newer/keep_larger/smart_conflict三种冲突策略与protectModifyPercentage删除保护阈值在不丢数据与正确传播变更之间取得了平衡。对于希望深入源码的读者推荐按以下顺序阅读仓库文件设计文档 → 面向用户的功能核对表 → V2 对照文档 → 核心实现 pro/src/sync.ts重点看getSyncPlanInplace与dispatchOperationToActualV3→ 冲突策略 pro/src/conflictLogic.ts → 升级弹窗 src/syncAlgoV3Notice.ts。赞分享数据同步【免费下载链接】remotely-saveSync notes between local and cloud with smart conflict: S3 (Amazon S3/Cloudflare R2/Backblaze B2/...), Dropbox, webdav (NextCloud/InfiniCLOUD/Synology/...), OneDrive, Google Drive (GDrive), Box, pCloud, Yandex Disk, Koofr, Azure Blob Storage.项目地址https://gitcode.com/gh_mirrors/re/remotely-save点击查看免费下载相关推荐Remotely Save 同步算法 V3 深度解析基于决策分支表的健壮双向同步与删除追踪设计Remotely Save 同步算法 V3 深度解析基于决策分支表的健壮双向同步与删除追踪设计 导读 本文围绕 Remotely Save 插件Obsidi数据同步Remotely Save 同步算法 V3 详解删除追踪、冲突处理与迁移机制Remotely Save 同步算法 V3 详解删除追踪、冲突处理与迁移机制 本文基于 Remotely Save 官方文档 docs/sync_algori数据同步Remotely Save 同步算法 V2 解析四大数据源、四时间戳决策表与文件夹递归删除规则Remotely Save 同步算法 V2 解析四大数据源、四时间戳决策表与文件夹递归删除规则 本文以 Remotely SaveObsidian 本地库与数据同步创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表