Skip to main content

atmos/kernel/fs/
btree.rs

1// btree.rs - Disk-based Copy-on-Write (COW) B-Tree for indexing filenames and labels
2#![allow(dead_code)]
3#![allow(static_mut_refs)]
4
5extern crate alloc;
6use alloc::vec::Vec;
7
8use super::block::{BlockDevice, MirroredBlockDevice, DATA_SIZE_PER_SECTOR};
9
10const MAX_KEYS: usize = 24;
11const KEY_LEN: usize = 16; // 128-bit hash
12
13/// ディスク上のB-Treeノード (データサイズ 508 バイト = セクタデータ領域ちょうど)。
14/// 挿入は「挿入→満杯なら分割」方式のため num_keys は分割直前に一時的に MAX_KEYS+1 まで増える。
15/// その一時オーバーフローを格納できるよう keys は MAX_KEYS+1、values は内部ノードの
16/// スライド (values[i+2]) と最右子ポインタを賄うため MAX_KEYS+2 を確保する。
17/// 永続化されるノードの num_keys は分割により常に MAX_KEYS 以下。
18#[repr(C, packed)]
19#[derive(Clone, Copy)]
20pub struct BTreeNode {
21    pub node_type: u8, // 0: Leaf, 1: Internal
22    pub num_keys: u8,
23    pub padding: [u8; 2],
24    pub keys: [[u8; KEY_LEN]; MAX_KEYS + 1], // UTF-8 キー配列 (+1 = 分割前の一時オーバーフロー)
25    pub values: [u32; MAX_KEYS + 2], // 葉:Metadataセクタ / 内部:子ノードセクタ (+2 = 一時オーバーフロー)
26}
27
28// BTreeNode は 1 セクタのデータ領域 (508B) にちょうど収まる必要がある。
29// keys/values の容量を変えてここを超えると to_bytes/from_bytes が領域外アクセスするため、
30// コンパイル時に検知する。
31const _: () = assert!(core::mem::size_of::<BTreeNode>() <= DATA_SIZE_PER_SECTOR);
32
33impl BTreeNode {
34    pub fn new(is_leaf: bool) -> Self {
35        Self {
36            node_type: if is_leaf { 0 } else { 1 },
37            num_keys: 0,
38            padding: [0; 2],
39            keys: [[0; KEY_LEN]; MAX_KEYS + 1],
40            values: [0; MAX_KEYS + 2],
41        }
42    }
43
44    /// バイトスライスから復元
45    pub fn from_bytes(bytes: &[u8]) -> Self {
46        let mut node = Self::new(true);
47        let ptr = &mut node as *mut Self as *mut u8;
48        unsafe {
49            core::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, core::mem::size_of::<Self>());
50        }
51        node
52    }
53
54    /// バイトスライスへシリアライズ
55    pub fn to_bytes(&self) -> [u8; DATA_SIZE_PER_SECTOR] {
56        let mut buf = [0u8; DATA_SIZE_PER_SECTOR];
57        let ptr = self as *const Self as *const u8;
58        unsafe {
59            core::ptr::copy_nonoverlapping(ptr, buf.as_mut_ptr(), core::mem::size_of::<Self>());
60        }
61        buf
62    }
63
64    /// キー文字列の比較ヘルパー (ハッシュ値の単純比較)
65    fn compare_keys(a: &[u8; KEY_LEN], b: &[u8]) -> core::cmp::Ordering {
66        let b_len = b.len().min(KEY_LEN);
67        let mut b_padded = [0u8; KEY_LEN];
68        b_padded[..b_len].copy_from_slice(&b[..b_len]);
69        a.cmp(&b_padded)
70    }
71}
72
73/// ディスク上のCOW B-Treeインデックスマネージャ
74pub struct CowBTree {
75    root_sector: u32,
76}
77
78impl CowBTree {
79    pub fn new(root_sector: u32) -> Self {
80        Self { root_sector }
81    }
82
83    pub fn get_root(&self) -> u32 {
84        self.root_sector
85    }
86
87    /// 指定したキーを B-Tree から検索します (O(log N) 探索)
88    /// 成功すると、指し示されているファイルメタデータセクタ番号を返します。
89    pub fn search<B: BlockDevice>(
90        &self,
91        device: &mut MirroredBlockDevice<B>,
92        key: &[u8; KEY_LEN],
93    ) -> Option<u32> {
94        let mut curr_sector = self.root_sector;
95        let mut buf = [0u8; DATA_SIZE_PER_SECTOR];
96        let mut loop_count = 0;
97
98        while curr_sector != 0 {
99            loop_count += 1;
100            if loop_count > 100 {
101                crate::println!(
102                    "      [BTree DBG] search loop exceeded 100 iterations! curr_sector={}",
103                    curr_sector
104                );
105                return None;
106            }
107            if device.read_sector(curr_sector as usize, &mut buf).is_err() {
108                return None;
109            }
110            let node = BTreeNode::from_bytes(&buf);
111
112            // 現在のノード内を探索
113            let mut idx = 0;
114            while idx < node.num_keys as usize {
115                if idx >= MAX_KEYS {
116                    crate::println!(
117                        "      [BTree DBG] search node num_keys is corrupted! num_keys={}",
118                        node.num_keys
119                    );
120                    return None;
121                }
122                let cmp = BTreeNode::compare_keys(&node.keys[idx], key);
123                if cmp == core::cmp::Ordering::Equal {
124                    if node.node_type == 0 {
125                        // 葉ノード: メタデータセクタ番号を返す
126                        return Some(node.values[idx]);
127                    } else {
128                        // 内部ノード: 次の子ノードへ遷移
129                        idx += 1;
130                        break;
131                    }
132                } else if cmp == core::cmp::Ordering::Greater {
133                    break;
134                }
135                idx += 1;
136            }
137
138            if node.node_type == 0 {
139                break; // 葉ノードで見つからなかった
140            } else {
141                curr_sector = node.values[idx]; // 子ノードセクタへ下る
142            }
143        }
144
145        None
146    }
147
148    /// インデックスへ新しいキーとセクタのペアを挿入します (COWによる再帰的ツリー更新)
149    /// 更新された新しいルートノードのセクタ番号を返します。
150    pub fn insert<B: BlockDevice>(
151        &mut self,
152        device: &mut MirroredBlockDevice<B>,
153        key: &[u8; KEY_LEN],
154        val_sector: u32,
155        alloc_sector_fn: &mut dyn FnMut() -> u32,
156    ) -> Result<u32, &'static str> {
157        let root_sec = self.root_sector;
158
159        // 1. ルートがまだ存在しない場合、新しい葉ノードを作成
160        if root_sec == 0 {
161            let new_sec = alloc_sector_fn();
162            if new_sec == 0 {
163                return Err("btree: sector allocation failed");
164            }
165
166            let mut new_node = BTreeNode::new(true);
167            new_node.num_keys = 1;
168            new_node.keys[0] = *key;
169            new_node.values[0] = val_sector;
170
171            device.write_sector(new_sec as usize, &new_node.to_bytes())?;
172            self.root_sector = new_sec;
173            return Ok(new_sec);
174        }
175
176        // 2. COW 再帰挿入の実行
177        let result = self.insert_recursive(device, root_sec, key, val_sector, alloc_sector_fn)?;
178
179        match result {
180            InsertResult::Ok(new_sec) => {
181                self.root_sector = new_sec;
182                Ok(new_sec)
183            }
184            InsertResult::Split(new_sec, split_key, split_sibling_sec) => {
185                // ルートノードが分割された場合、新しいルート(内部ノード)を作成
186                let new_root_sec = alloc_sector_fn();
187                if new_root_sec == 0 {
188                    return Err("btree: sector allocation failed");
189                }
190
191                let mut new_root = BTreeNode::new(false);
192                new_root.num_keys = 1;
193                new_root.keys[0] = split_key;
194                new_root.values[0] = new_sec;
195                new_root.values[1] = split_sibling_sec;
196
197                device.write_sector(new_root_sec as usize, &new_root.to_bytes())?;
198                self.root_sector = new_root_sec;
199                Ok(new_root_sec)
200            }
201        }
202    }
203
204    /// すべての葉ノードエントリ (key, value_sector) を収集
205    pub fn collect_leaf_entries<B: BlockDevice>(
206        &self,
207        device: &mut MirroredBlockDevice<B>,
208        out: &mut Vec<([u8; KEY_LEN], u32)>,
209    ) {
210        if self.root_sector == 0 {
211            return;
212        }
213        let mut visited = Vec::new();
214        self.collect_from_node(device, self.root_sector, out, &mut visited);
215    }
216
217    fn collect_from_node<B: BlockDevice>(
218        &self,
219        device: &mut MirroredBlockDevice<B>,
220        sector: u32,
221        out: &mut Vec<([u8; KEY_LEN], u32)>,
222        visited: &mut Vec<u32>,
223    ) {
224        if visited.contains(&sector) {
225            crate::println!(
226                "      [BTree DBG] Circular reference detected in collect_from_node: sector={}",
227                sector
228            );
229            return;
230        }
231        visited.push(sector);
232        if visited.len() > 100 {
233            crate::println!("      [BTree DBG] Recursion limit exceeded in collect_from_node!");
234            return;
235        }
236
237        let mut buf = [0u8; DATA_SIZE_PER_SECTOR];
238        if device.read_sector(sector as usize, &mut buf).is_err() {
239            return;
240        }
241
242        let node = BTreeNode::from_bytes(&buf);
243        if node.node_type == 0 {
244            let limit = (node.num_keys as usize).min(MAX_KEYS);
245            for i in 0..limit {
246                out.push((node.keys[i], node.values[i]));
247            }
248            return;
249        }
250
251        let limit = (node.num_keys as usize).min(MAX_KEYS);
252        for i in 0..=limit {
253            let child = node.values[i];
254            if child != 0 {
255                self.collect_from_node(device, child, out, visited);
256            }
257        }
258    }
259
260    /// COW を保ちつつ、B-Treeに再帰的に挿入を行います。
261    fn insert_recursive<B: BlockDevice>(
262        &self,
263        device: &mut MirroredBlockDevice<B>,
264        curr_sector: u32,
265        key: &[u8; KEY_LEN],
266        val_sector: u32,
267        alloc_sector_fn: &mut dyn FnMut() -> u32,
268    ) -> Result<InsertResult, &'static str> {
269        let mut buf = [0u8; DATA_SIZE_PER_SECTOR];
270        // 【2026-08-05】ここは `?` で `read_sector` のエラーをそのまま返していた。
271        //
272        // 実測で `[CACHE] 保存に失敗 ... err=read_sector: sector out of range`
273        // が出続けており、5.3MB のフォントも 8KB の JS も保存できていない
274        // (=毎回 14MB を取り直している)。だが原文のエラーだけでは
275        // **どのセクタが範囲外なのか、どこから来た番号なのか**が分からず、
276        // 原因に辿り着けなかった。
277        //
278        // 木の節点番号が実在範囲を外れているのは索引の破損なので、
279        // 値と範囲を添えて報告する(推測で直さないための情報を残す)。
280        if curr_sector as usize >= device.total_usable_sectors() {
281            crate::warn!(
282                "[SylFS][BTREE] 節点番号が実在範囲外 curr_sector={} usable={} (索引が壊れている)",
283                curr_sector,
284                device.total_usable_sectors()
285            );
286            return Err("btree: node sector out of range");
287        }
288        if let Err(e) = device.read_sector(curr_sector as usize, &mut buf) {
289            crate::warn!(
290                "[SylFS][BTREE] 節点の読み出しに失敗 curr_sector={} usable={} err={}",
291                curr_sector,
292                device.total_usable_sectors(),
293                e
294            );
295            return Err(e);
296        }
297
298        // COW: 読み込んだノードを新しいセクタにコピーして書き換える準備をする
299        let mut node = BTreeNode::from_bytes(&buf);
300        let new_sector = alloc_sector_fn();
301        if new_sector == 0 {
302            return Err("btree: sector allocation failed");
303        }
304
305        // 現在のノード内での挿入位置を二分探索/線形探索
306        let mut idx = 0;
307        while idx < node.num_keys as usize {
308            let cmp = BTreeNode::compare_keys(&node.keys[idx], key);
309            if cmp == core::cmp::Ordering::Equal {
310                if node.node_type == 0 {
311                    // 葉ノード: すでに同じキーが存在 → 値(メタデータセクタ)を上書き更新
312                    node.values[idx] = val_sector;
313                    device.write_sector(new_sector as usize, &node.to_bytes())?;
314                    return Ok(InsertResult::Ok(new_sector));
315                } else {
316                    // 内部ノード: 分離キーと一致した場合、実体は右部分木の葉にある(B+Tree)。
317                    // search と同様に右の子へ降下する(values[idx] を上書きすると部分木を破壊する)。
318                    idx += 1;
319                    break;
320                }
321            } else if cmp == core::cmp::Ordering::Greater {
322                break;
323            }
324            idx += 1;
325        }
326
327        if node.node_type == 0 {
328            // --- 葉ノード (Leaf) への直接挿入 ---
329            // キーと値をスライドさせて挿入
330            for i in (idx..node.num_keys as usize).rev() {
331                node.keys[i + 1] = node.keys[i];
332                node.values[i + 1] = node.values[i];
333            }
334            node.keys[idx] = *key;
335            node.values[idx] = val_sector;
336            node.num_keys += 1;
337
338            if node.num_keys as usize > MAX_KEYS {
339                // 分割 (Split) が発生
340                let split_res = self.split_node(device, &mut node, new_sector, alloc_sector_fn)?;
341                Ok(split_res)
342            } else {
343                // 分割なし
344                device.write_sector(new_sector as usize, &node.to_bytes())?;
345                Ok(InsertResult::Ok(new_sector))
346            }
347        } else {
348            // --- 内部ノード (Internal) への再帰的挿入 ---
349            let child_sec = node.values[idx];
350            let sub_result =
351                self.insert_recursive(device, child_sec, key, val_sector, alloc_sector_fn)?;
352
353            match sub_result {
354                InsertResult::Ok(new_child_sec) => {
355                    // 子ノードがCOWで新しいセクタに切り替わったため、ポインタを更新
356                    node.values[idx] = new_child_sec;
357                    device.write_sector(new_sector as usize, &node.to_bytes())?;
358                    Ok(InsertResult::Ok(new_sector))
359                }
360                InsertResult::Split(new_child_sec, split_key, split_sibling_sec) => {
361                    // 子ノードが分割されたため、分割キーと新しい兄弟へのポインタを親ノード(自分)に挿入
362                    node.values[idx] = new_child_sec;
363
364                    for i in (idx..node.num_keys as usize).rev() {
365                        node.keys[i + 1] = node.keys[i];
366                        node.values[i + 2] = node.values[i + 1];
367                    }
368                    node.keys[idx] = split_key;
369                    node.values[idx + 1] = split_sibling_sec;
370                    node.num_keys += 1;
371
372                    if node.num_keys as usize > MAX_KEYS {
373                        // 親ノードもさらに分割
374                        let split_res =
375                            self.split_node(device, &mut node, new_sector, alloc_sector_fn)?;
376                        Ok(split_res)
377                    } else {
378                        device.write_sector(new_sector as usize, &node.to_bytes())?;
379                        Ok(InsertResult::Ok(new_sector))
380                    }
381                }
382            }
383        }
384    }
385
386    /// ノードの半分を別の新しいセクタに分割し、親への引き上げ情報を返します (COW対応)
387    fn split_node<B: BlockDevice>(
388        &self,
389        device: &mut MirroredBlockDevice<B>,
390        node: &mut BTreeNode,
391        new_sector: u32,
392        alloc_sector_fn: &mut dyn FnMut() -> u32,
393    ) -> Result<InsertResult, &'static str> {
394        let sibling_sector = alloc_sector_fn();
395        if sibling_sector == 0 {
396            return Err("btree: sector allocation failed");
397        }
398
399        let mut sibling = BTreeNode::new(node.node_type == 0);
400        // 実際の num_keys を基準に分割する (一時オーバーフロー時は MAX_KEYS+1)。
401        let n = node.num_keys as usize;
402        let mid = n / 2;
403
404        // 親に引き上げる分離キー
405        let split_key = node.keys[mid];
406
407        if node.node_type == 0 {
408            // --- 葉ノード (B+Tree): 中央キーは右兄弟に残し、分離キーとしてコピー引き上げ。
409            //     キーを取りこぼさないよう右兄弟は keys[mid..n] を受け取る。
410            let sibling_keys_num = n - mid;
411            for i in 0..sibling_keys_num {
412                sibling.keys[i] = node.keys[mid + i];
413                sibling.values[i] = node.values[mid + i];
414            }
415            sibling.num_keys = sibling_keys_num as u8;
416        } else {
417            // --- 内部ノード (B-Tree): 中央キーは親へ移動し子からは除去。
418            //     右兄弟は keys[mid+1..n] と対応する子ポインタ values[mid+1..n+1] を受け取る。
419            let sibling_keys_num = n - mid - 1;
420            for i in 0..sibling_keys_num {
421                sibling.keys[i] = node.keys[mid + 1 + i];
422                sibling.values[i] = node.values[mid + 1 + i];
423            }
424            sibling.values[sibling_keys_num] = node.values[n]; // 最右子ポインタ
425            sibling.num_keys = sibling_keys_num as u8;
426        }
427
428        // 前半のノードサイズを縮小 (左ノードは keys[0..mid] を保持)
429        node.num_keys = mid as u8;
430
431        // 両ノードをそれぞれ別の空きセクタに書き込み (COW)
432        device.write_sector(new_sector as usize, &node.to_bytes())?;
433        device.write_sector(sibling_sector as usize, &sibling.to_bytes())?;
434
435        Ok(InsertResult::Split(new_sector, split_key, sibling_sector))
436    }
437}
438
439/// 挿入再帰処理の結果
440enum InsertResult {
441    /// 通常終了。新しいセクタ番号を返す。
442    Ok(u32),
443    /// 分割発生。新しいセクタ番号、引き上げられるキー、および新しい右側の兄弟セクタを返す。
444    Split(u32, [u8; KEY_LEN], u32),
445}