Skip to main content

atmos/os_lib/web_engine/
queue_batch.rs

1//! 取得待ち行列から「まとめ取得する分」を選ぶ判定(純粋モジュール)。
2//!
3//! 仕様は `spec/resource_loading.md`。
4//!
5//! # なぜ純粋関数に切り出すのか
6//!
7//! 【2026-08-05】同一ホストをまとめて 1 接続で取る機能を 5 回配線して
8//! 5 回とも `[NET][STATS] total=3` でページが読めなくなった。
9//!
10//! 原因は取得処理ではなかった(`[KADIAG]` を入れたら、
11//! **まとめ取得の関数は一度も呼ばれていない**のに止まっていた)。
12//!
13//! 兄弟をまとめる処理は待ち行列から項目を**取り除く**。
14//! ところが「取り除いたが条件によっては使わない」経路があると、
15//! その項目はどこにも戻らず**消える**。
16//! 消えたリソースは二度と取得されないので、ページが完成しない。
17//!
18//! そこで **「取り出す前に、取り出してよいかを決める」** 形にし、
19//! その判定をここへ切り出して単体試験で固定する
20//! (`tests/src/test_queue_batch.rs`)。
21
22/// まとめ取得の候補を選ぶための、1 項目ぶんの情報。
23///
24/// 待ち行列の要素そのものではなく**判定に要る分だけ**を持つ。
25/// 文字列を持たないので試験が書きやすい。
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub struct Candidate {
28    /// ホストが選定対象と同じか。
29    pub same_host: bool,
30    /// 優先度が選定対象と同じか。
31    pub same_priority: bool,
32    /// HTTPS か(HTTP はまとめ取得の対象外)。
33    pub is_https: bool,
34    /// 一度まとめ取得で失敗して「次は個別に取る」印が付いているか。
35    pub no_batch: bool,
36}
37
38/// そもそもまとめ取得を始めてよいか。**取り出す前に**呼ぶ。
39///
40/// ここで `false` なら待ち行列には一切触らない。
41/// 「取り出したのに使わない」経路を作らないための入口。
42///
43/// - `main_in_flight` … メイン HTML を取得中か。
44///   まとめ取得は 1 本のワーカーを長く占有するので、
45///   メインの取得と競合させない。
46/// - `picked_is_https` / `picked_no_batch` … 選んだ項目自身の性質。
47pub fn may_start_batch(
48    main_in_flight: bool,
49    picked_is_https: bool,
50    picked_no_batch: bool,
51) -> bool {
52    !main_in_flight && picked_is_https && !picked_no_batch
53}
54
55/// まとめ取得へ載せる項目の添字を選ぶ。
56///
57/// `may_start_batch` が `true` のときだけ呼ぶこと。
58/// 返した添字の項目は**必ず**まとめ取得へ渡す
59/// (取り出したまま使わない経路を作らない)。
60///
61/// 返す添字は昇順。呼び出し側が後ろから取り除けば添字がずれない。
62///
63/// 計算量: **O(N)**(N は待ち行列の長さ)。
64pub fn select_batch(cands: &[Candidate], max: usize) -> alloc::vec::Vec<usize> {
65    let mut out = alloc::vec::Vec::new();
66    if max == 0 {
67        return out;
68    }
69    for (i, c) in cands.iter().enumerate() {
70        if out.len() >= max {
71            break;
72        }
73        if c.same_host && c.same_priority && c.is_https && !c.no_batch {
74            out.push(i);
75        }
76    }
77    out
78}