1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//! 集成测试共用的 tempdir 收尾辅助——四个曾经在 Windows 上 flaky 过的测试文件
//! (reconcile/e2e_watch/incremental/ocr_pipeline)都用这一份,别各自维护一套。
//!
//! flaky 根因:tantivy 的 mmap/合并线程、notify 的目录句柄、OCR worker 释放
//! 句柄不一定跟"测试函数认为自己用完了"这个时间点同步,`TempDir` 默认的
//! `Drop`/`close()` 都只尝试一次 `remove_dir_all`,撞上还没释放的句柄就直接
//! 报 `PermissionDenied`。测试收尾要:
//! 1. 显式 drop 掉持有索引/OCR 句柄的对象(`Searcher`/`IndexUpdater`/
//! `OcrPipeline` 等),让句柄有机会先释放;
//! 2. 再用生产代码同款的重试退避逻辑([`dowse::remove_dir_all_retrying`])
//! 删掉临时目录,而不是指望 `TempDir::close()` 的单次尝试。
//!
//! 另外还带了 [`force_slow_lane_for_tests`]:让普通集成测试确定性地跳过
//! CI 管理员环境下的整卷 MFT 快速枚举,见该函数文档。
/// 关掉一个 `TempDir`,删除失败时按重试退避逻辑再试。
///
/// 不走 `TempDir::close()`——它内部也只是单次 `remove_dir_all`,撞上未释放的
/// 句柄一样会报错,而且 `close()` 一旦返回错误,目录多半没删干净、又没有
/// 办法在同一个 `TempDir` 上再重试一次(`close` 消费了 `self`)。这里改成
/// `keep()` 拿到路径本身(放弃 `TempDir` 自身的自动清理——我们接下来手动删,
/// 不需要它再删一次),直接调重试版本的 `remove_dir_all`。
/// 逃生舱开关:调一次就够,让本进程接下来所有 `rebuild_index`/`watch_roots_auto`
/// 调用确定性地走 walkdir + notify 慢车道,不管跑机是不是管理员——见
/// `dowse`(`volume.rs`)里 `DOWSE_FORCE_SLOW_LANE` 的文档。
///
/// 只给"只需要索引能用"的普通集成测试用(ocr_pipeline/e2e_watch/incremental/
/// reconcile/multi_root/office_extract)。`tests/ntfs_fast_path.rs` 专门验证
/// 真快车道本身,绝不能调这个函数。
///
/// 调用方要求:每个会触碰 `rebuild_index`/`watch_roots_auto` 的 `#[test]` 函数
/// 自己在最前面调一次——不是"某个测试调了全局就生效"那种隐式约定。原因:
/// Rust 集成测试同一个二进制内的多个 `#[test]` 默认并行跑在不同线程,
/// `env::set_var`(2024 edition 起标记 unsafe)不是线程安全的写入;用 `Once`
/// 收敛后,不管多少个测试线程同时调用这个函数,实际只会执行一次真正的
/// `set_var`,且 `call_once` 保证所有线程从这个函数返回时那次写入已经完成
/// ——只要调用方遵守"用之前先调"这一条,就不会有别的测试线程读到设置到一半
/// 的环境变量。
///
/// `common/mod.rs` 按源码整份编入每个 `mod common;` 的测试二进制——
/// `ntfs_fast_path.rs` 也 `mod common;`(用它的 `close_tempdir_retrying`),
/// 但按上面的规则绝不会调这个函数,因此在那个二进制里这两项天然"没被用到";
/// `#[allow(dead_code)]` 就是为了那一个二进制不被 `-D warnings` 判死,不代表
/// 这份代码本身没人用(另外 5 个测试文件都在用)。
static FORCE_SLOW_LANE_INIT: Once = new;