Himalaya pimdir 队列可见性:让暂存写入在下一次同步前即时可见
CLI【免费下载链接】himalayaCLI to manage emails项目地址https://gitcode.com/gh_mirrors/hi/himalaya点击查看免费下载导读本文以 Himalaya 项目中pimdir-queue-visibility变更提案cairn/changes/pimdir-queue-visibility/proposal.md为骨架剖析 pimdir 离线缓存后端“写入进队列、读取看索引”分离后遗留的可见性缺口以及 Himalaya 如何通过叠加读取overlay、排队计数报告与**pimdir queue子命令**三件套将其补齐。读完本文你将理解暂存的set-flags/remove/move/copy/update为何能立即反映到列表排队的创建消息为何“报告而不列出”以及如何用himalaya pimdir queue list查看、用queue cancel撤回一条尚未被同步引擎应用的排队消息——包括为什么“排空队列draining”在这里不是正确答案。问题缘起写入与读取之间隔着一整条同步队列pimdir-producer-reader变更让 Himalaya 同时成为 pimdir 存储的读者reader与生产者producer写入被“暂存stage”为追加到存储队列中的动作action读取则是已提交索引committed index的投影。这两者之间原本没有任何连接——于是出现了一个让用户恐慌的窗口期给一封邮件打上旗标列表里旗标立刻消失移动一封邮件它停留在原处。数据什么都没丢下一次同步后变更会落地但在这段窗口期内Himalaya 报告出的存储状态与用户刚刚执行的操作互相矛盾。对一个以 GB 计的邮件存储来说这种矛盾被用户读作“数据丢失”——这正是一个邮件客户端能收到的最糟糕的误读proposal 原文称之为 the worst reading available。值得强调的是这一缺口并非架构设计上的意外pimdir SPEC §15.4 早已允许读取方把某个集合的待处理动作pending actions叠加overlay到其投影之上而PimdirProducer::pending_actions也已能给出这些行——只是 Himalaya 从未调用它。本变更的实质就是把规范预留的能力真正接入客户端读取路径。为什么“排空队列”不是答案在给出修复方案之前提案专门用一段写明了为什么不能靠 Himalaya 自己排空队列以免该方案被再次提出队列行没有 source 列排空方drainer需要自己盖上来源stage_action从PimdirSourceStore取 source绑定bindings以(collection, link_id, source)为键一旦排空方不是同步引擎就会把变更以“没有任何东西会推送的 source”暂存出去——静默失败而 Himalaya 在pimdir.source被移除后连可以盖的 source 都没有所以即使在原理上也无法正确排空。结论明确Himalaya 保持“读者 生产者”的定位把排空和应用交给存储的所有者同步引擎日志中称为 Neverest。这也是queue cancel为何必须走“所有者owner作用域操作”的根本原因——撤消一个排队动作是所有者才有的写权限。修复方案一读路径叠加待处理动作核心改动集中在 src/pimdir/client.rsPimdirClient不再持有普通 store 句柄而是持有一个叠加了待处理动作的PimdirReader// src/pimdir/client.rs#L56-L60 // NOTE: reads overlay the queue, so what this client staged shows on // the next read rather than on the next sync. let store PimdirReader::open(root) .map_err(|err| anyhow!(Open pimdir store {}: {err}, root.display()))? .with_pending();with_pending()让五种针对已存在消息的动作在下次读取时立即可见暂存动作效果set-flags刚加上的旗标在重新列出时仍然在remove刚删除的消息从列表消失动作仍排队等待所有者应用move消息出现在目标邮箱的列表copy副本出现在目标邮箱的列表update更新后的摘要反映在列表关键在于这五种动作都保留了消息的seq因此“消息如何被寻址”没有任何变化Envelope.id依旧是一个String——叠加只改变列表显示什么绝不改变消息如何被寻址a staged write changes what a listing shows and never how a message is addressed。需求方delta.md还明确了一条边界停放parked的动作不得显示为已暂存——它没有操作者就不会被应用按“待处理”读取等于向用户许诺做不到的事。修复方案二排队创建“报告而不列出”set-flags、remove、move、copy、update都有现成的消息可寻址但一条排队中的创建queued create没有seq——在同步引擎所有者应用它之前它不存在于索引中也就没有 id 可以放进信封envelope。提案明确否决了三种“发明 id”的做法0或空字符串它们是标识符空间内的取值却什么也不命名q前缀的令牌这是另一个空间的 id却要被塞进每个命令都会读回的字段里。所以排队创建不是被投影成信封而是被报告出来。add_message已经返回它暂存时的 link id——这才是跨越整个窗口期标识一条创建的正确句柄。落到实现上src/shared/envelope/list.rs 的Envelopes结构新增了queued: usize字段L175在表格下方渲染为N queued messages, see himalaya pimdir queue list见 L245-L251 的实现0时不输出1时输出单数形式其余输出复数。该字段同样参与--json序列化。对其他所有后端而言该值恒为 0——它们的写入即时到达服务器0 才是事实因此这个字段是“最小公分母”而非 pimdir 专属的琐碎细节。两个细节值得注意envelope search一律报告 nonesrc/pimdir/backend.rs 的search_envelopesL155-L176排队创建从不参与查询匹配一个过滤器从未见过的计数比没有计数更糟计数出现的时机是“用户正困惑的那一刻”——列表里没有刚保存的消息——而不是保存那一刻因此它真正阻止了问题报告的产生。修复方案三himalaya pimdir queue list—— 把排队创建渲染成邮件pimdir 的操作者 CLI 是**类型无关kind-agnostic**的只会打印 id、哈希和旗标而 Himalaya 持有 blob 与邮件约定可以做得更多。pimdir queue list命令把排队创建渲染成真正的邮件视图。命令树src/pimdir/cli.rs、src/pimdir/queue/cli.rshimalaya pimdir queue list # 别名 ls列出某邮箱排队的创建与发送 himalaya pimdir queue cancel ROW # 撤回一行确认后执行除非 --yeslist的实现src/pimdir/queue/list.rs以MailboxArg定位邮箱调用PimdirClient::queued_envelopes(mailbox)输出一张六列表格ROWACTIONFLAGSSUBJECTTOQUEUED行 id供 cancel 使用save/send旗标字形主题收件人排队时间戳关键字段PimdirQueuedMessageL78-L92idi64队列行 id命名的是待处理动作而非消息——消息在被同步引擎应用前没有 id应用后也会得到另一个不同的 idqueued_at行被追加的时刻来自存储自身的时钟——即“年龄”的来源producer暂存它的进程名本仓库恒为himalayasend该行是发送send而非归档saveenvelope从动作钉住的 blob 中重新推导出的摘要其id为空排队消息尚无 id。空队列输出No message queued in this mailbox非空时表格尾部附一行引导Queued until the next sync. Cancel one with himalaya pimdir queue cancel ROW表格样式预设、各列颜色、未读/回复/旗标字形全部复用账号的envelope list配置table_preset、envelopes_list_table_*等与普通列表观感一致。修复方案四himalaya pimdir queue cancel ROW—— 唯一的撤回通道src/pimdir/queue/cancel.rs 的PimdirQueueCancelCommand接收两个参数/// Row id of the staged message, as pimdir queue list prints it. #[arg(value_name ROW)] pub id: i64, /// Do not ask for confirmation. #[arg(long, short)] pub yes: bool,执行流程除非--yes否则弹出布尔确认Cancel the message queued as row {id}?拒绝则Cancellation aborted调用PimdirClient::cancel_queued(id)经 io-pimdir 的作用域化所有者操作scoped owner operation对应 pimdir SPEC §15.5撤回一行成功输出Queued message {id} cancelled若行已不存在报No queued action with row {id}; it may have been synced already。cancel_queued的实现src/pimdir/client.rs#L99-L108体现了三条设计约束pub fn cancel_queued(self, id: i64) - Resultbool { PimdirStore::cancel_action(self.root, id).map_err(|err| match err { PimdirError::Owned(_) anyhow!( A sync is running on {}, so the queue cannot be edited; \ the action may have been applied already, self.root.display(), ), err anyhow!(Cancel queued action {id}: {err}), }) }角色最短持有所有者角色只在这一次调用内进入并释放Himalaya 从不持有能排空队列或收集存储的句柄src/pimdir/backend.rs 的读写路径也绝不触碰所有者角色同步期间快速失败fail-fast另一进程同步引擎正在排空存储时立即拒绝并说明“同步正在进行、动作可能已被应用”而不是抛出一个锁错误——因为动作仍在排队用户读到消息时它可能已经被应用了message save的确认文案不变共享命令的措辞不因后端而异proposal 明确 The shared commands do not vary their wording by backend。此外delta 需求还规定一个接受公开 id 的命令如果被问及一条排队创建应当拒绝并点名 cancel 命令而不是报告“未知消息”。从需求到验证测试与落地记录变更需求delta.md以场景形式固化了验收标准离线加旗标后仍在对无同步排空的 pimdir 账号加旗标并重新列出 → 消息带着旗标离线删除后离开列表删除消息并重新列出 → 它从列表消失动作仍在队列中等待所有者保存的消息说明去向向 pimdir 邮箱保存消息且尚未同步 → 列表不新增信封但报告“1 queued message”并点名himalaya pimdir queue list撤回排队的草稿对未被同步应用的排队创建执行queue cancel→ 行消失正文留给收集器collector邮箱不再报告排队消息同步期间撤回Neverest 正在排空存储 → 撤回立即失败说明同步正在进行、动作可能已被应用。实现层面的测试位于 src/pimdir/backend.rs如a_sent_message_is_one_submit_row_with_its_envelopeL852-L897以及“排队创建渲染为带空 id 的邮件”“只有创建动作出现在队列视图暂存的删除因寻址已存在的消息而无从渲染”对应的任务清单见 tasks.md。落地日志 2026-08-27-pimdir-queue-visibility.md 记录118 个测试全部通过且变更期间在 io-pimdir 上游发现并依赖其修复了一个缺陷overlay-page-is-total——叠加页可能在集合中间提前变短暂存删除会从已返回结果中抽走一行导致基于 keyset 分页的全集合扫描提前终止、静默丢弃后续消息本变更因此依赖该上游补丁。延后事项Envelope.id保持String提案明确将“排队创建是否该进入message list”判定为v1 问题若答案是肯定的届时采用Envelope.id: OptionString以null编码“尚未分配 id”——这是诚实的编码也是纯增量的改动。但在草稿 UXdrafts UX证明有必要之前不值得为所有后端拓宽共享信封结构。小结pimdir-queue-visibility变更把 Himalaya 的 pimdir 后端从一个“与用户操作脱节”的只读投影变成了一套自洽的读写体验读路径叠加src/pimdir/client.rs 的PimdirReader::with_pending()让针对存量消息的五种暂存动作即时可见且不改动消息寻址方式、Envelope.id维持String排队创建“报告而不列出”src/shared/envelope/list.rs 的Envelopes.queued在用户最困惑的时刻列表里找不到刚保存的消息给出解释并点名查看命令把“数据丢失”误读扼杀在源头pimdir queue list/queue cancelsrc/pimdir/queue/list.rs、src/pimdir/queue/cancel.rs用邮件视图补上了“跨窗口期标识排队创建”的最后一块拼图并以作用域化的所有者操作、同步期快速失败、确认提示--yes跳过完整定义了撤回的语义边界。整套方案始终恪守一条原则Himalaya 是读者和生产者不越权成为排空者——把应用动作的权力留给存储的所有者同时让用户在下一次同步之前就清楚地看到自己做过什么、这些东西去了哪里。赞分享CLI【免费下载链接】himalayaCLI to manage emails项目地址https://gitcode.com/gh_mirrors/hi/himalaya点击查看免费下载相关推荐json-render 的 shadcn/ui 组件库用 json-render/shadcn 构建生成式 UIjson render 的 shadcn/ui 组件库用 json render/shadcn 构建生成式 UI json render/shadcn 是CLINacos Config 一致性、Dump 与可见性全解析写入可见性、集群传播与本地缓存刷新机制Nacos Config 一致性、Dump 与可见性全解析写入可见性、集群传播与本地缓存刷新机制 Nacos 配置中心的核心承诺是配置变更最终可见一条配后端微服务配置中心服务注册发现云原生Blackbird 使用指南快速搜索 600 平台的用户名与邮箱附免费 AI 画像Blackbird 使用指南快速搜索 600 平台的用户名与邮箱附免费 AI 画像 你手里拿到一个陌生的用户名想知道这个人是否还活跃在 Reddit、G网络安全网页爬虫CLI上一篇深度解析PC端微信/QQ/TIM消息保留技术完全手册下一篇微信QQ防撤回终极指南Windows平台消息保留与多开完整解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考