SSH 文件读取器在元数据之前保留无关流¶
文件读取器在等待自身元数据期间会排队所有文件流通知。因此,延迟读取会保留来自其他已完成读取的负载。修复通过 mux 现有的同步 beforeResolve 回调安装元数据,并在读取拥有流标识之前忽略通知。监听器仍在请求之前注册,且与响应相邻的自身帧会被正确处理。
这是在待处理的元数据请求期间发生的有条件临时保留。该证明确立了源机制及其修正;它没有识别受影响的主机,没有测量自然原生 I/O 停顿,也没有将 #19831 归因于 SSH。
实际生产者与所有权链¶
- 桌面端
filesystem-read-handlers.ts为fs:readFile调用所选的SshFilesystemProvider.readFile;该路由不会串行化读取。运行时预览也会使用该 provider,并带有调用方特定的上限。AI-vault 扫描具有八操作门控,它仍允许在一个操作等待时,其他槽位中反复完成。 readFileViaStream在发送fs.readFileStream之前订阅 chunk/end/error 通知。此前,它会追加所有此类通知,直到元数据 promise 的.then回调运行,即使它们属于其他流。- Relay
FilesystemHandler将路径和请求上下文转发给readRelayFileStreamMetadata。生产者在获取流槽位之前等待stat。对于未知 MIME 类型,其前缀探测也先于注册。在打开/注册文件后,它使用setImmediate调度其泵并返回元数据。 RelayDispatcher在其控制通道中发布小型元数据响应;写入器在批量之前优先处理控制。写满的写入器控制验证在排空后元数据先于 chunk。- mux 在响应分发期间同步运行
beforeResolve,先于解析请求 promise。其解码器可以在任何.then回调运行之前分发相邻通知。修复在该同步边界安装流 ID 和缓冲区,消除了保存外部帧的需要。
生产者、mux、分发器、解码器、写入器、文件 I/O 和流注册表是可移植证明中的实际源代码。测试夹具通过内存双工传输连接两端,使用真实临时文件,并提供文件系统处理器的小型路径/客户端/节奏适配器。它不会启动 SSH 进程、Electron 窗口、原生 PTY 或网络服务器。
边界与负载共享¶
- Relay 允许 16 个并发已注册流,每个限速流具有 四 chunk ACK 窗口。chunk 为 256 KiB。在注册前等待的元数据操作不占用流槽位。其他传输可以完成并反复重用槽位。
- 读取器大小上限为 10 MiB 文本 / 50 MiB 二进制,可选地由调用方收紧。它们在该读取器的元数据之后应用,并且不会计入其之前累积的外部历史。
- 元数据请求具有 30,000 ms 截止期限。元数据之后,读取器使用 60,000 ms 非活动截止期限,由其自身 chunk 重置,并与挂起/恢复集成。连接释放也会释放订阅。这些定时器和传输吞吐量限制了普通保留时长;挂起/事件循环停顿可能延迟定时器。未确立无限期原生停顿。
- 解码器将每个轮次限制为 64 帧 / 4 ms,并限制保留的帧字节。这些限制不会限制帧解析后由订阅者拥有的数组。
- mux 将 相同的已解析 params 对象传递给所有订阅者。四个等待读取器每帧添加四个包装器,但共享其负载。结果不是四个复制的负载,也不是二次方负载字节增长。
比较结果¶
所有 80 个可移植用例通过:十个控制 × 基线/修复 × 已审计工作树/命名主图 × Node/Electron。Node 为 26.6;Electron 43.7 使用 Node 24.21。报告记录精确版本、所有 59 个选定源哈希、观察到的读取器哈希以及证明工件哈希。
| 观察项 | 修复前 | 修复后 |
|---|---|---|
| 四个等待中的读取器;16 个已完成的 2 MiB 传输 | 576 个包装器 | 0 |
| 保留的唯一共享 params 对象 | 144 | 0 |
| 逻辑 base64 字节数,每个唯一 params 对象只计一次 | 44,739,584 | 0 |
| 该工作负载中的峰值已注册流 | 1 | 1 |
| 已处理的 ACK | 128 | 128 |
| 元数据完成、已处理释放或截止后的读取器历史 | 已释放 | 已释放 |
| 实际泵在 ACK 投递被扣留时 | 在 4 个 chunk 后停止 | 相同 |
| 十六条活动流,随后第十七条请求 | 拒绝;后续准入成功 | 相同 |
| 写满的写入器,然后排空 | 元数据先于自身 chunk | 相同 |
| 响应加上自身 chunk/end 在一个解码器轮次中 | 正确结果 | 相同 |
| 未限速生产者 / 普通完成 | 正确结果 | 相同 |
| 规范 LF 与合成 CRLF 源/补丁读取 | 66 次读取一致 | 相同 |
主要可移植工作负载有意在 调用实际 relay 文件生产者之前 门控四个请求处理器。请求保持待处理,同时其他真实传输完成。这种受控适配器延迟不同于已在进行中的原生 stat;生产源代码确立了等待 stat 发生在同一注册前阶段。它没有测量原生元数据 I/O 延迟在用户机器上发生的频率或时长。
基线观察仅添加 WeakRef(pending) 以暴露闭包中的数组。它不添加强引用所有者。共享参数身份在所有等待读取者之间检查。堆差值支持对象/字节核算,但既不是精确对象大小,也不是 RSS。释放后,测试消费惰性的 Error.stack 并仅保留错误代码:外部保留的未实例化 V8 错误堆栈本身可能保留回调上下文,因此释放声明在正常错误处理之后。
每次成功传输都会检查载荷长度和 SHA-256。流容量、节奏、取消和输出断言在两个变体中相同运行。受控生产者在一个情况下忽略 ACK 节奏;这测试现有的无节奏行为,而不是每个历史中继二进制。
源图与发布¶
source-versions.json 记录完整的 59 个模块导入图以及五个额外的实际调用者哈希。两个图选择相同的文件读取器源变体。经过审计的工作树和指定 main 291b4ddd6f1c1af480169885e0fda7f9c78ff053 除此之外仅先前发布的 SSH 写入器已消费前缀修正不同。
main-context.patch 在内存中重建该单一上下文差异。加载器接受其两个精确记录的检出哈希中的任意一个,并重建所选图。这使得同一工件可以在该工作树或独立的 main 发布上运行,而不依赖另一个内存 PR。fix.patch 是正在审查的独立、单产品文件变更。其他所有图/调用者源都受哈希保护;未知生产导入会失败。专用可移植测试省略无关的全局 Vitest 设置文件。
当前读取器基线和中继文件生产者也与 v1.4.198(e0826956fcfc532f5a1e55b5e081f2e57e553c43)逐字节相同。该指定版本具有同步的 beforeResolve 和控制优先的写入器调度。其比较仅限于记录的路径;证明不执行整个历史应用。
没有线路字段、操作码、主机执行判定、流上限、超时、回退或原生进程生命周期变更。现有的 MethodNotFound 回退以及格式错误元数据 / 更紧上限 / 空图像 / 相邻错误处理通过永久回归测试套件经由实际 mux 覆盖。
复现¶
选择任一图(worktree 或 main)和变体(before 或 fixed):
ORCA_BACKGROUND_LAUNCH=1 ORCA_SSH_READER_GRAPH=main ORCA_SSH_READER_VARIANT=fixed pnpm exec vitest run --config docs/audits/ssh-file-metadata-retention/vitest.config.mjs
对于 Electron,使用 ELECTRON_RUN_AS_NODE=1 和 ORCA_BACKGROUND_LAUNCH=1 调用已安装的 Electron 二进制文件,并传入 node_modules/vitest/vitest.mjs 以及相同参数。每个图/变体/运行时的报告都是分开的。将 ORCA_SSH_READER_OUTPUT 设置为替代文件路径以保留捕获的报告。
永久测试和有意基线失败:
ORCA_BACKGROUND_LAUNCH=1 pnpm exec vitest run --config config/vitest.config.ts src/main/ssh/ssh-filesystem-stream-retention.test.ts src/main/providers/ssh-filesystem-provider-stream.test.ts src/main/providers/ssh-filesystem-provider.test.ts src/main/ssh/ssh-channel-multiplexer.test.ts src/relay/fs-handler-stream.test.ts
ORCA_BACKGROUND_LAUNCH=1 pnpm exec vitest run --config docs/audits/ssh-file-metadata-retention/before.config.mjs src/main/ssh/ssh-filesystem-stream-retention.test.ts src/main/providers/ssh-filesystem-provider-stream.test.ts
基线在元数据保持待处理时保留所有 64 个观察到的外部帧对象,导致恰好新的生命周期断言失败;其他 22 个测试通过。初始四套件运行通过 70 个测试。详细质量/typecheck 结果在 validation.json 中。全文件转换诊断是原始读取器和提供者测试中相同的 15 个继承断言,通过精确诊断/源跨度比较验证;变更代码门报告没有新发现。没有抑制任何 lint 规则,也没有为满足该基线清理而更改无关的线路验证行为。
扩展的五套件运行通过 124 个测试,包括通用提供者套件。空文件对照使用现有流式测试夹具,该夹具在解析元数据前调用 mux 的 beforeResolve 回调,并验证所有流监听器均已释放。旧版通用测试夹具省略了该回调并复现了 CI 超时;实际 mux 空元数据对照已经通过。此修正仅更改测试设置。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 orca48/orca