use std::io; use std::path::Path; use crate::page::{Page, PageFile, PageId}; // 磁盘 B+ 树:键是变长字节串,允许重复键,叶子链支持范围扫描。 const META_PAGE: PageId = 0; const META_MAGIC: &[u8; 4] = b"CBK2"; const OFF_PAGE_SIZE: usize = 4; const OFF_MAX_KEY: usize = 8; const OFF_ROOT: usize = 10; const OFF_ORDER: usize = 18; const NODE_LEAF: u8 = 0; const NODE_INTERNAL: u8 = 1; const OFF_KIND: usize = 0; const OFF_COUNT: usize = 1; const OFF_NEXT: usize = 3; const HEADER: usize = 11; const SLOT: usize = 2; const CELL_FIXED: usize = 2 + 8; /// 键长上限:节点里的格子必须放得进一页 pub const MAX_KEY_BYTES: usize = 64; /// 一个节点最多几个键 fn max_keys(order: usize) -> usize { order - 1 } /// 一个格子最多占多少字节 fn max_cell_bytes() -> usize { CELL_FIXED + MAX_KEY_BYTES } /// 这个 order 放得进一页吗 pub fn fits_in_page(page_size: usize, order: usize) -> bool { order >= 2 && HEADER + max_keys(order) * (SLOT + max_cell_bytes()) <= page_size } /// 一页最多几个孩子 pub fn max_order(page_size: usize) -> usize { page_size.saturating_sub(HEADER) / (SLOT + max_cell_bytes()) + 1 } /// 读一个 u8 fn read_u8(p: &Page, off: usize) -> u8 { p.data[off] } /// 写一个 u8 fn write_u8(p: &mut Page, off: usize, v: u8) { p.data[off] = v; } /// 读一个小端 u16 fn read_u16(p: &Page, off: usize) -> u16 { u16::from_le_bytes([p.data[off], p.data[off + 1]]) } /// 写一个小端 u16 fn write_u16(p: &mut Page, off: usize, v: u16) { p.data[off..off + 2].copy_from_slice(&v.to_le_bytes()); } /// 读一个小端 u32 fn read_u32(p: &Page, off: usize) -> u32 { u32::from_le_bytes([p.data[off], p.data[off + 1], p.data[off + 2], p.data[off + 3]]) } /// 写一个小端 u32 fn write_u32(p: &mut Page, off: usize, v: u32) { p.data[off..off + 4].copy_from_slice(&v.to_le_bytes()); } /// 读一个小端 u64 fn read_u64(p: &Page, off: usize) -> u64 { let mut b = [0u8; 8]; b.copy_from_slice(&p.data[off..off + 8]); u64::from_le_bytes(b) } /// 写一个小端 u64 fn write_u64(p: &mut Page, off: usize, v: u64) { p.data[off..off + 8].copy_from_slice(&v.to_le_bytes()); } /// 写文件头 fn write_meta(page: &mut Page, page_size: usize, order: usize, root: PageId) { page.zero(); page.data[0..4].copy_from_slice(META_MAGIC); write_u32(page, OFF_PAGE_SIZE, page_size as u32); write_u16(page, OFF_MAX_KEY, MAX_KEY_BYTES as u16); write_u64(page, OFF_ROOT, root); write_u16(page, OFF_ORDER, order as u16); } /// 校验文件头与配置 fn check_meta(page: &Page, page_size: usize, order: usize) -> io::Result<()> { if page.data[0..4] != *META_MAGIC { return Err(io::Error::new( io::ErrorKind::InvalidData, "not a chusql index file (bad magic)", )); } let stored_page = read_u32(page, OFF_PAGE_SIZE) as usize; let stored_order = read_u16(page, OFF_ORDER) as usize; if stored_page != page_size || stored_order != order { return Err(io::Error::new( io::ErrorKind::InvalidData, format!( "index file was built with page.size={} btree.order={}, config says page.size={} btree.order={}", stored_page, stored_order, page_size, order ), )); } Ok(()) } /// 一个节点:叶子存行位置,内部节点存孩子页号 struct Node { kind: u8, next: PageId, keys: Vec>, values: Vec, } /// 一个格子占多少字节 fn cell_bytes(key: &[u8]) -> usize { CELL_FIXED + key.len() } /// 节点占多少字节 fn node_bytes(node: &Node) -> usize { HEADER + node.keys.len() * SLOT + node.keys.iter().map(|k| cell_bytes(k)).sum::() } /// 把节点写回一页(格子从页尾往前摆,槽位从头部往后长) fn put_node(p: &mut Page, node: &Node) -> io::Result<()> { if node.keys.len() > u16::MAX as usize || node_bytes(node) > p.data.len() { return Err(io::Error::new( io::ErrorKind::InvalidInput, "index node does not fit in a page", )); } p.zero(); write_u8(p, OFF_KIND, node.kind); write_u16(p, OFF_COUNT, node.keys.len() as u16); // 内部节点比键多一个孩子,最后一个放在 next 槽位里 let trailer = if node.kind == NODE_INTERNAL { node.values.last().copied().unwrap_or(0) } else { node.next }; write_u64(p, OFF_NEXT, trailer); let mut cursor = p.data.len(); for (i, key) in node.keys.iter().enumerate() { let size = cell_bytes(key); cursor -= size; write_u16(p, cursor, key.len() as u16); p.data[cursor + 2..cursor + 2 + key.len()].copy_from_slice(key); write_u64(p, cursor + 2 + key.len(), node.values[i]); write_u16(p, HEADER + i * SLOT, cursor as u16); } Ok(()) } /// 从一页读出节点 fn get_node(p: &Page) -> Node { let kind = read_u8(p, OFF_KIND); let count = read_u16(p, OFF_COUNT) as usize; let trailer = read_u64(p, OFF_NEXT); let mut keys = Vec::with_capacity(count); let mut values = Vec::with_capacity(count + 1); for i in 0..count { let off = read_u16(p, HEADER + i * SLOT) as usize; let klen = read_u16(p, off) as usize; keys.push(p.data[off + 2..off + 2 + klen].to_vec()); values.push(read_u64(p, off + 2 + klen)); } if kind == NODE_INTERNAL { values.push(trailer); Node { kind, next: 0, keys, values } } else { Node { kind, next: trailer, keys, values } } } /// 叶子里的插入位置:同键按 value 排,保证顺序稳定 fn leaf_slot(keys: &[Vec], values: &[u64], key: &[u8], value: u64) -> usize { let mut i = keys.partition_point(|k| k.as_slice() < key); while i < keys.len() && keys[i].as_slice() == key && values[i] < value { i += 1; } i } /// 内部节点里选哪个孩子 fn child_slot(keys: &[Vec], key: &[u8]) -> usize { keys.partition_point(|k| k.as_slice() <= key) } /// 切开一个节点:返回上提的键与右半节点 fn split_node(node: &mut Node) -> (Vec, Node) { let mid = node.keys.len() / 2; if node.kind == NODE_LEAF { let sep = node.keys[mid].clone(); let right = Node { kind: NODE_LEAF, next: node.next, keys: node.keys.split_off(mid), values: node.values.split_off(mid), }; (sep, right) } else { let sep = node.keys[mid].clone(); let right_keys = node.keys.split_off(mid + 1); let right_values = node.values.split_off(mid + 1); node.keys.pop(); ( sep, Node { kind: NODE_INTERNAL, next: 0, keys: right_keys, values: right_values }, ) } } /// 磁盘 B+ 树 pub struct DiskBTree { file: PageFile, order: usize, } impl DiskBTree { /// 打开或新建索引文件 pub fn open>( path: P, page_size: usize, order: usize, pool_size: usize, ) -> io::Result { if !fits_in_page(page_size, order) { return Err(io::Error::new( io::ErrorKind::InvalidInput, format!( "btree order {} does not fit in a {}-byte page (max {})", order, page_size, max_order(page_size) ), )); } let mut file = PageFile::with_options(path, page_size, pool_size)?; if file.num_pages()? == 0 { let mut meta = Page::new(META_PAGE, page_size); write_meta(&mut meta, page_size, order, 0); file.write_page(&meta)?; } else { let meta = file.read_page(META_PAGE)?; check_meta(&meta, page_size, order)?; } Ok(DiskBTree { file, order }) } /// 键太长直接报错,避免写坏节点 fn check_key(&self, key: &[u8]) -> io::Result<()> { if key.len() > MAX_KEY_BYTES { return Err(io::Error::new( io::ErrorKind::InvalidInput, format!( "index key is {} bytes, at most {} are supported", key.len(), MAX_KEY_BYTES ), )); } Ok(()) } /// 读根页页号;空树是 None fn root(&mut self) -> io::Result> { let r = self.file.with_page(META_PAGE, |p| read_u64(p, OFF_ROOT))?; Ok(if r == 0 { None } else { Some(r) }) } /// 写根页页号 fn set_root(&mut self, r: Option) -> io::Result<()> { self.file .update_page(META_PAGE, |p| write_u64(p, OFF_ROOT, r.unwrap_or(0))) } /// 追加一个新节点页 fn alloc(&mut self, node: &Node) -> io::Result { let page = self.file.append_page()?; let id = page.id; self.file.update_page(id, |p| put_node(p, node))??; Ok(id) } /// 按页号读节点 fn load(&mut self, id: PageId) -> io::Result { self.file.with_page(id, get_node) } /// 按页号写节点 fn store(&mut self, id: PageId, node: &Node) -> io::Result<()> { self.file.update_page(id, |p| put_node(p, node))? } /// 清空整棵树 pub fn clear(&mut self) -> io::Result<()> { let page_size = self.file.page_size(); self.file.truncate()?; let mut meta = Page::new(META_PAGE, page_size); write_meta(&mut meta, page_size, self.order, 0); self.file.write_page(&meta)?; Ok(()) } /// 树是空的吗(只看最左叶子,不用整树遍历) pub fn is_empty(&mut self) -> io::Result { let Some(mut id) = self.root()? else { return Ok(true); }; loop { let node = self.load(id)?; if node.kind == NODE_LEAF { return Ok(node.keys.is_empty()); } id = node.values[0]; } } /// 按 key 取第一个位置 pub fn get(&mut self, key: &[u8]) -> io::Result> { Ok(self.get_all(key)?.into_iter().next()) } /// 按 key 取全部位置(重复键按值升序) pub fn get_all(&mut self, key: &[u8]) -> io::Result> { let Some(mut id) = self.root()? else { return Ok(Vec::new()); }; loop { let node = self.load(id)?; if node.kind == NODE_LEAF { let start = node.keys.partition_point(|k| k.as_slice() < key); let mut out = Vec::new(); for i in start..node.keys.len() { if node.keys[i].as_slice() != key { break; } out.push(node.values[i]); } return Ok(out); } id = node.values[child_slot(&node.keys, key)]; } } /// 插入一个键值对(键可重复) pub fn insert(&mut self, key: &[u8], value: u64) -> io::Result<()> { self.check_key(key)?; match self.root()? { None => { let node = Node { kind: NODE_LEAF, next: 0, keys: vec![key.to_vec()], values: vec![value], }; let id = self.alloc(&node)?; self.set_root(Some(id)) } Some(root) => match self.insert_rec(root, key, value)? { None => Ok(()), Some((sep, right_id)) => { let node = Node { kind: NODE_INTERNAL, next: 0, keys: vec![sep], values: vec![root, right_id], }; let id = self.alloc(&node)?; self.set_root(Some(id)) } }, } } /// 递归插入,溢出就把右半节点与上提键交给上层 fn insert_rec( &mut self, id: PageId, key: &[u8], value: u64, ) -> io::Result, PageId)>> { let mut node = self.load(id)?; if node.kind == NODE_LEAF { let at = leaf_slot(&node.keys, &node.values, key, value); node.keys.insert(at, key.to_vec()); node.values.insert(at, value); } else { let child = node.values[child_slot(&node.keys, key)]; if let Some((sep, right_id)) = self.insert_rec(child, key, value)? { let at = node.keys.partition_point(|k| k.as_slice() <= sep.as_slice()); node.keys.insert(at, sep); node.values.insert(at + 1, right_id); } } if node.keys.len() <= max_keys(self.order) { self.store(id, &node)?; return Ok(None); } let (sep, mut right) = split_node(&mut node); let right_id = self.alloc(&right)?; if node.kind == NODE_LEAF { right.next = node.next; node.next = right_id; } self.store(id, &node)?; Ok(Some((sep, right_id))) } /// 删掉一个 (key, value) pub fn delete(&mut self, key: &[u8], value: u64) -> io::Result { let Some(root) = self.root()? else { return Ok(false); }; self.delete_rec(root, key, value) } /// 递归删一个 (key, value) fn delete_rec(&mut self, id: PageId, key: &[u8], value: u64) -> io::Result { let mut node = self.load(id)?; if node.kind == NODE_LEAF { let at = leaf_slot(&node.keys, &node.values, key, value); if at < node.keys.len() && node.keys[at].as_slice() == key && node.values[at] == value { node.keys.remove(at); node.values.remove(at); self.store(id, &node)?; return Ok(true); } return Ok(false); } let child = node.values[child_slot(&node.keys, key)]; self.delete_rec(child, key, value) } /// 叶子链上按顺序取全部 (键, 值) pub fn iter_all(&mut self) -> io::Result, u64)>> { self.scan(None, None) } /// 范围扫描:lo / hi 都是闭区间,None 表示不限 pub fn scan( &mut self, lo: Option<&[u8]>, hi: Option<&[u8]>, ) -> io::Result, u64)>> { let Some(mut id) = self.root()? else { return Ok(Vec::new()); }; loop { let node = self.load(id)?; if node.kind == NODE_LEAF { id = match lo { None => id, Some(start) => { let at = node.keys.partition_point(|k| k.as_slice() < start); if at < node.keys.len() { id } else { node.next } } }; break; } id = match lo { None => node.values[0], Some(start) => node.values[child_slot(&node.keys, start)], }; } let mut out = Vec::new(); while id != 0 { let node = self.load(id)?; for i in 0..node.keys.len() { if lo.is_some_and(|start| node.keys[i].as_slice() < start) { continue; } if hi.is_some_and(|end| node.keys[i].as_slice() > end) { return Ok(out); } out.push((node.keys[i].clone(), node.values[i])); } id = node.next; } Ok(out) } /// 脏页写回 pub fn flush(&mut self) -> io::Result<()> { self.file.flush() } /// 当前缓存页数 pub fn cached_pages(&self) -> usize { self.file.cached_pages() } }