Skip to content

fix(search): bound workspace queries with cancellable multi-root snapshots - #1116

Open
kogekiplay wants to merge 3 commits into
spacering-net:mainfrom
kogekiplay:fix/memory-search-latest
Open

kogekiplay wants to merge 3 commits into
spacering-net:mainfrom
kogekiplay:fix/memory-search-latest

Conversation

@kogekiplay

@kogekiplay kogekiplay commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

工作区搜索原来会在输入框挂载时把整个目录列表送进每个渲染端,并生成路径、小写副本和 JS 对象。一个真实工作区此前测得 5,308,089 条条目、970,417,831 字节 JSON;旧客户端仅启动页面就发起 8 次全量列表请求。

本 PR 将发现、索引和排名留在原生端。前端只接收当前查询的结果(API 最多 200 条),输入框挂载和关闭的搜索窗口都不触发发现。已补齐原草稿的调度、多根缓存和超预算复用问题。

实现

  • 锁外发现和评分:registry 只短暂查表和发布;目录发现最多 2 个 worker、评分 4 个、空查询另有 2 个。大根发现不会占住全局遍历锁,小根查询和空查询可以独立完成。
  • 查询生命周期:无后台预热,旧 prepare endpoint 为兼容 no-op。同根发现合并;一个等待者关闭不影响其他等待者,最后一个离开则取消排队/进行中的发现。过期查询、卸载、掉线请求和后继世代都不能发布部分或陈旧快照。
  • 多根 LRU:最多 8 根、共用 128 MiB 保留内存预算;2 个 builder 共用 192 MiB 构建上限。淘汰但仍被查询持有的 snapshot lease 继续计入预算。根按 canonical path、授权链接和根 ignore-file metadata 区分,A → B → A 可以复用。
  • 超预算磁盘快照:同一次遍历写入完整的临时二进制 snapshot,超过 compact index 预算后释放内存 builder。后续查询以独立 positional cursor 分页读取,保留 top-k,不再为每个按键遍历文件系统。总磁盘预算 2 GiB、每根最多 1 GiB;失败有 5 秒 backoff,部分快照永不发布。
  • 自动清理:使用 tempfile::tempfile,Unix 创建即 unlink,Windows delete-on-close;取消、失败、淘汰和进程退出都关闭文件。无需新增数据库依赖或持久目录迁移。
  • 保留查询取消与 bounded transport,修复渐进建议的分组/引用选中项、窗口 focus 和 ES2020 测试兼容问题。生产包中不再包含全量 list_workspace_files 或 prepare 调用。

实现与边界见 docs/workspace-search-design.md。

验证

基于最新官方 main c340c76e34075da83602712e07352b543e6aa380,本次提交 c4c095c8。

  • Frozen install、完整 TypeScript(包含测试)、全仓 ESLint、production build 通过;Vitest 770 文件、11,420 项通过。
  • 新调度/缓存聚焦测试 23 项通过,1 项真实大目录手动测试默认忽略。覆盖阻塞大根时查询小根/空查询、双消费者、排队/最后消费者取消、旧世代竞态、A/B/A、canonical alias、授权撤销、TTL/refresh、LRU、disk overflow/backoff、活跃 lease 配额、并发磁盘读和排名一致性。
  • Desktop cargo check、clippy --all-targets --features test-utils -- -D warnings 通过。Desktop 完整 tests(含集成及 doc tests)共 6,784 项通过、7 项忽略,仅过滤下述本机网络测试;相关签名测试单独及最终全量复跑通过。
  • Server cargo check、完整 lib/bin tests(6,366 项通过、6 项忽略)和 clippy -D warnings 通过,最终 head 复验同样通过。MCP-only cargo check 和 clippy -D warnings 也通过。

本机既有测试限制:commands::remote_proxy::tests::an_event_socket_gets_past_an_address_that_never_answers 在本机 IPv6/TEST-NET 超时场景下失败,单独复跑也超时。相关 remote_proxy.rs 与官方 main 逐字节相同,本 PR 未改这项测试;完整未过滤首轮失败如实保留,最终本地 desktop 轮次仅过滤这一项。当前 head 的远端 CI 单独核对。

真实大目录测量与限制

在 /Users/kogeki/dev 的真实大目录上(debug binary、并行进行其他测试),连续三次查询只遍历 1 次:

查询轮次 耗时 返回字节 文件系统遍历次数
首次发现并评分 213.5 s 916 B 1
复用磁盘快照 32.4 s 1,013 B 1
再次复用 39.9 s 741 B 1

快照 833,353,343 B(约 795 MiB),保留 compact-index bytes 为 0;单独测试进程物理 footprint 峰值约 109.4 MiB、末次约 17.4 MiB。该测量在 basename 剪枝的最后一次小优化前完成,只用于证明发现复用/预算行为,不冒充最终 head 的性能基准。

磁盘评分仍为 O(N),首次发现和超大目录的后续查询仍可能慢;这不是常数时间索引,也不能证明整个 Codeg 的长期内存增长已全部解决。嵌套 ignore/普通文件变化按 5 分钟 TTL 或显式 refresh 更新。内存预算针对索引、构建及评分工作集,OS page cache、文件遍历器和进程其他模块不在此会计内。

Refs #1097

@kogekiplay
kogekiplay force-pushed the fix/memory-search-latest branch from 62da274 to b64ef86 Compare November 10, 2026 10:13
@kogekiplay kogekiplay changed the title refactor(search): stage native search and foreground scheduling proposal refactor(search): bound renderer results and defer discovery to queries Nov 10, 2026
@xintaofei

Copy link
Copy Markdown
Collaborator

codeg work task 497 is done — it made no changes, so nothing was pushed to this pull request.

@kogekiplay
kogekiplay force-pushed the fix/memory-search-latest branch from b64ef86 to c4c095c Compare November 11, 2026 02:47
@kogekiplay kogekiplay changed the title refactor(search): bound renderer results and defer discovery to queries fix(search): bound workspace queries with cancellable multi-root snapshots Nov 11, 2026
@kogekiplay
kogekiplay marked this pull request as ready for review November 11, 2026 02:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants