大更新:
1、完善SQL语法 2、移除node前端,只保留静态资源 3、写好安装脚本 4、做好linux适配
This commit is contained in:
1 parent
687c012841
commit
df6d348995
166 files changed
+16317
-10763
No files matched your search
+314
-303
@@ -3,84 +3,77 @@ use std::path::Path;
|
||||
|
||||
use crate::page::{Page, PageFile, PageId};
|
||||
|
||||
// 磁盘 B+ 树:节点占一页,文件头记页大小与 order。
|
||||
// 磁盘 B+ 树:键是变长字节串,允许重复键,叶子链支持范围扫描。
|
||||
|
||||
const META_PAGE: PageId = 0;
|
||||
const META_MAGIC: &[u8; 4] = b"CBTR";
|
||||
const OFF_META_PAGE_SIZE: usize = 4;
|
||||
const OFF_META_ORDER: usize = 8;
|
||||
const OFF_META_ROOT: usize = 10;
|
||||
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_TYPE: usize = 0;
|
||||
const OFF_KIND: usize = 0;
|
||||
const OFF_COUNT: usize = 1;
|
||||
const OFF_NEXT: usize = 3;
|
||||
const OFF_KEYS: usize = 12;
|
||||
const HEADER: usize = 11;
|
||||
const SLOT: usize = 2;
|
||||
const CELL_FIXED: usize = 2 + 8;
|
||||
|
||||
/// 一个节点占多少字节
|
||||
fn node_bytes(order: usize) -> usize {
|
||||
OFF_KEYS + max_keys(order) * 8 + order * 8
|
||||
}
|
||||
/// 键长上限:节点里的格子必须放得进一页
|
||||
pub const MAX_KEY_BYTES: usize = 64;
|
||||
|
||||
/// 最多几个键
|
||||
/// 一个节点最多几个键
|
||||
fn max_keys(order: usize) -> usize {
|
||||
order - 1
|
||||
}
|
||||
|
||||
/// 值区域的起点
|
||||
fn off_payload(order: usize) -> usize {
|
||||
OFF_KEYS + max_keys(order) * 8
|
||||
/// 一个格子最多占多少字节
|
||||
fn max_cell_bytes() -> usize {
|
||||
CELL_FIXED + MAX_KEY_BYTES
|
||||
}
|
||||
|
||||
/// 这个 order 放得进一页吗
|
||||
pub fn fits_in_page(page_size: usize, order: usize) -> bool {
|
||||
order >= 2 && node_bytes(order) <= page_size
|
||||
order >= 2 && HEADER + max_keys(order) * (SLOT + max_cell_bytes()) <= page_size
|
||||
}
|
||||
|
||||
/// 一页最多几个孩子
|
||||
pub fn max_order(page_size: usize) -> usize {
|
||||
page_size.saturating_sub(4) / 16
|
||||
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());
|
||||
}
|
||||
@@ -89,9 +82,10 @@ fn write_u64(p: &mut Page, off: usize, v: u64) {
|
||||
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_META_PAGE_SIZE, page_size as u32);
|
||||
write_u16(page, OFF_META_ORDER, order as u16);
|
||||
write_u64(page, OFF_META_ROOT, root);
|
||||
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);
|
||||
}
|
||||
|
||||
/// 校验文件头与配置
|
||||
@@ -102,8 +96,8 @@ fn check_meta(page: &Page, page_size: usize, order: usize) -> io::Result<()> {
|
||||
"not a chusql index file (bad magic)",
|
||||
));
|
||||
}
|
||||
let stored_page = read_u32(page, OFF_META_PAGE_SIZE) as usize;
|
||||
let stored_order = read_u16(page, OFF_META_ORDER) as usize;
|
||||
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,
|
||||
@@ -116,89 +110,114 @@ fn check_meta(page: &Page, page_size: usize, order: usize) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
enum NodeData {
|
||||
Leaf {
|
||||
keys: Vec<i64>,
|
||||
values: Vec<u64>,
|
||||
next: PageId,
|
||||
},
|
||||
Internal {
|
||||
keys: Vec<i64>,
|
||||
children: Vec<PageId>,
|
||||
},
|
||||
/// 一个节点:叶子存行位置,内部节点存孩子页号
|
||||
struct Node {
|
||||
kind: u8,
|
||||
next: PageId,
|
||||
keys: Vec<Vec<u8>>,
|
||||
values: Vec<u64>,
|
||||
}
|
||||
|
||||
/// 一个格子占多少字节
|
||||
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::<usize>()
|
||||
}
|
||||
|
||||
/// 把节点写回一页(格子从页尾往前摆,槽位从头部往后长)
|
||||
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 read_node(p: &Page, order: usize) -> NodeData {
|
||||
let ty = read_u8(p, OFF_TYPE);
|
||||
let n = read_u16(p, OFF_COUNT) as usize;
|
||||
let payload = off_payload(order);
|
||||
if ty == NODE_LEAF {
|
||||
let next = read_u64(p, OFF_NEXT);
|
||||
let mut keys = Vec::with_capacity(n);
|
||||
let mut values = Vec::with_capacity(n);
|
||||
for i in 0..n {
|
||||
keys.push(read_u64(p, OFF_KEYS + i * 8) as i64);
|
||||
values.push(read_u64(p, payload + i * 8));
|
||||
}
|
||||
NodeData::Leaf { keys, values, next }
|
||||
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 {
|
||||
let mut keys = Vec::with_capacity(n);
|
||||
let mut children = Vec::with_capacity(n + 1);
|
||||
for i in 0..n {
|
||||
keys.push(read_u64(p, OFF_KEYS + i * 8) as i64);
|
||||
}
|
||||
for i in 0..(n + 1) {
|
||||
children.push(read_u64(p, payload + i * 8));
|
||||
}
|
||||
NodeData::Internal { keys, children }
|
||||
Node { kind, next: trailer, keys, values }
|
||||
}
|
||||
}
|
||||
|
||||
/// 把节点写回一页
|
||||
fn write_node(p: &mut Page, node: &NodeData, order: usize) {
|
||||
p.zero();
|
||||
let payload = off_payload(order);
|
||||
match node {
|
||||
NodeData::Leaf { keys, values, next } => {
|
||||
write_u8(p, OFF_TYPE, NODE_LEAF);
|
||||
write_u16(p, OFF_COUNT, keys.len() as u16);
|
||||
write_u64(p, OFF_NEXT, *next);
|
||||
for (i, k) in keys.iter().enumerate() {
|
||||
write_u64(p, OFF_KEYS + i * 8, *k as u64);
|
||||
}
|
||||
for (i, v) in values.iter().enumerate() {
|
||||
write_u64(p, payload + i * 8, *v);
|
||||
}
|
||||
}
|
||||
NodeData::Internal { keys, children } => {
|
||||
write_u8(p, OFF_TYPE, NODE_INTERNAL);
|
||||
write_u16(p, OFF_COUNT, keys.len() as u16);
|
||||
for (i, k) in keys.iter().enumerate() {
|
||||
write_u64(p, OFF_KEYS + i * 8, *k as u64);
|
||||
}
|
||||
for (i, c) in children.iter().enumerate() {
|
||||
write_u64(p, payload + i * 8, *c);
|
||||
}
|
||||
}
|
||||
/// 叶子里的插入位置:同键按 value 排,保证顺序稳定
|
||||
fn leaf_slot(keys: &[Vec<u8>], 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<u8>], key: &[u8]) -> usize {
|
||||
keys.partition_point(|k| k.as_slice() <= key)
|
||||
}
|
||||
|
||||
/// 切开一个节点:返回上提的键与右半节点
|
||||
fn split_node(node: &mut Node) -> (Vec<u8>, 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 },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// 二分选孩子
|
||||
fn child_index(keys: &[i64], key: i64) -> usize {
|
||||
let mut lo = 0;
|
||||
let mut hi = keys.len();
|
||||
while lo < hi {
|
||||
let mid = (lo + hi) / 2;
|
||||
if keys[mid] <= key {
|
||||
lo = mid + 1;
|
||||
} else {
|
||||
hi = mid;
|
||||
}
|
||||
}
|
||||
lo
|
||||
}
|
||||
|
||||
/// 磁盘 B+ 树
|
||||
pub struct DiskBTree {
|
||||
file: PageFile,
|
||||
order: usize,
|
||||
@@ -207,11 +226,11 @@ pub struct DiskBTree {
|
||||
impl DiskBTree {
|
||||
/// 打开或新建索引文件
|
||||
pub fn open<P: AsRef<Path>>(
|
||||
path: P,
|
||||
page_size: usize,
|
||||
order: usize,
|
||||
pool_size: usize,
|
||||
) -> io::Result<Self> {
|
||||
path: P,
|
||||
page_size: usize,
|
||||
order: usize,
|
||||
pool_size: usize,
|
||||
) -> io::Result<Self> {
|
||||
if !fits_in_page(page_size, order) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
@@ -235,21 +254,44 @@ impl DiskBTree {
|
||||
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(())
|
||||
}
|
||||
|
||||
fn root(&mut self) -> io::Result<Option<PageId>> {
|
||||
let r = self.file.with_page(META_PAGE, |p| read_u64(p, OFF_META_ROOT))?;
|
||||
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<PageId>) -> io::Result<()> {
|
||||
self.file
|
||||
.update_page(META_PAGE, |p| write_u64(p, OFF_META_ROOT, r.unwrap_or(0)))
|
||||
.update_page(META_PAGE, |p| write_u64(p, OFF_ROOT, r.unwrap_or(0)))
|
||||
}
|
||||
|
||||
/// 分配新页
|
||||
fn alloc(&mut self) -> io::Result<PageId> {
|
||||
Ok(self.file.append_page()?.id)
|
||||
fn alloc(&mut self, node: &Node) -> io::Result<PageId> {
|
||||
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<Node> {
|
||||
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))?
|
||||
}
|
||||
|
||||
/// 清空整棵树
|
||||
@@ -262,221 +304,190 @@ impl DiskBTree {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 空页,用来拼节点
|
||||
fn new_page(&self, id: PageId) -> Page {
|
||||
Page::new(id, self.file.page_size())
|
||||
}
|
||||
|
||||
/// 按 key 找 value
|
||||
pub fn get(&mut self, key: i64) -> io::Result<Option<u64>> {
|
||||
match self.root()? {
|
||||
None => Ok(None),
|
||||
Some(r) => self.get_rec(r, key),
|
||||
/// 树是空的吗(只看最左叶子,不用整树遍历)
|
||||
pub fn is_empty(&mut self) -> io::Result<bool> {
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
/// 递归查找
|
||||
fn get_rec(&mut self, page_id: PageId, key: i64) -> io::Result<Option<u64>> {
|
||||
let order = self.order;
|
||||
match self.file.with_page(page_id, |p| read_node(p, order))? {
|
||||
NodeData::Leaf { keys, values, .. } => {
|
||||
Ok(keys.binary_search(&key).ok().map(|i| values[i]))
|
||||
}
|
||||
NodeData::Internal { keys, children } => {
|
||||
let i = child_index(&keys, key);
|
||||
self.get_rec(children[i], key)
|
||||
/// 按 key 取第一个位置
|
||||
pub fn get(&mut self, key: &[u8]) -> io::Result<Option<u64>> {
|
||||
Ok(self.get_all(key)?.into_iter().next())
|
||||
}
|
||||
|
||||
/// 按 key 取全部位置(重复键按值升序)
|
||||
pub fn get_all(&mut self, key: &[u8]) -> io::Result<Vec<u64>> {
|
||||
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: i64, value: u64) -> io::Result<()> {
|
||||
/// 插入一个键值对(键可重复)
|
||||
pub fn insert(&mut self, key: &[u8], value: u64) -> io::Result<()> {
|
||||
self.check_key(key)?;
|
||||
match self.root()? {
|
||||
None => {
|
||||
let id = self.alloc()?;
|
||||
let node = NodeData::Leaf {
|
||||
keys: vec![key],
|
||||
values: vec![value],
|
||||
let node = Node {
|
||||
kind: NODE_LEAF,
|
||||
next: 0,
|
||||
keys: vec![key.to_vec()],
|
||||
values: vec![value],
|
||||
};
|
||||
let mut p = self.new_page(id);
|
||||
write_node(&mut p, &node, self.order);
|
||||
self.file.write_page(&p)?;
|
||||
let id = self.alloc(&node)?;
|
||||
self.set_root(Some(id))
|
||||
}
|
||||
Some(r) => {
|
||||
let (_, split) = self.insert_rec(r, key, value)?;
|
||||
if let Some((sep, right_id)) = split {
|
||||
let root_id = self.alloc()?;
|
||||
let node = NodeData::Internal {
|
||||
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],
|
||||
children: vec![r, right_id],
|
||||
values: vec![root, right_id],
|
||||
};
|
||||
let mut p = self.new_page(root_id);
|
||||
write_node(&mut p, &node, self.order);
|
||||
self.file.write_page(&p)?;
|
||||
self.set_root(Some(root_id))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 递归插入,可能上提
|
||||
fn insert_rec(
|
||||
&mut self,
|
||||
page_id: PageId,
|
||||
key: i64,
|
||||
value: u64,
|
||||
) -> io::Result<(PageId, Option<(i64, PageId)>)> {
|
||||
let order = self.order;
|
||||
let node = self.file.with_page(page_id, |p| read_node(p, order))?;
|
||||
let limit = max_keys(order);
|
||||
match node {
|
||||
NodeData::Leaf { mut keys, mut values, next } => {
|
||||
match keys.binary_search(&key) {
|
||||
Ok(i) => values[i] = value,
|
||||
Err(i) => {
|
||||
keys.insert(i, key);
|
||||
values.insert(i, value);
|
||||
}
|
||||
}
|
||||
if keys.len() <= limit {
|
||||
self.file.update_page(page_id, |p| {
|
||||
write_node(p, &NodeData::Leaf { keys, values, next }, order)
|
||||
})?;
|
||||
Ok((page_id, None))
|
||||
} else {
|
||||
let mid = keys.len() / 2;
|
||||
let rkeys = keys.split_off(mid);
|
||||
let rvalues = values.split_off(mid);
|
||||
let sep = rkeys[0];
|
||||
|
||||
let right_id = self.alloc()?;
|
||||
let mut rp = self.new_page(right_id);
|
||||
write_node(
|
||||
&mut rp,
|
||||
&NodeData::Leaf { keys: rkeys, values: rvalues, next },
|
||||
order,
|
||||
);
|
||||
self.file.write_page(&rp)?;
|
||||
|
||||
self.file.update_page(page_id, |p| {
|
||||
write_node(p, &NodeData::Leaf { keys, values, next: right_id }, order)
|
||||
})?;
|
||||
|
||||
Ok((page_id, Some((sep, right_id))))
|
||||
}
|
||||
}
|
||||
|
||||
NodeData::Internal { mut keys, mut children } => {
|
||||
let i = child_index(&keys, key);
|
||||
let (new_child, split) = self.insert_rec(children[i], key, value)?;
|
||||
children[i] = new_child;
|
||||
match split {
|
||||
None => {
|
||||
self.file.update_page(page_id, |p| {
|
||||
write_node(p, &NodeData::Internal { keys, children }, order)
|
||||
})?;
|
||||
Ok((page_id, None))
|
||||
}
|
||||
Some((sep, right_id)) => {
|
||||
keys.insert(i, sep);
|
||||
children.insert(i + 1, right_id);
|
||||
if keys.len() <= limit {
|
||||
self.file.update_page(page_id, |p| {
|
||||
write_node(p, &NodeData::Internal { keys, children }, order)
|
||||
})?;
|
||||
Ok((page_id, None))
|
||||
} else {
|
||||
let mid = keys.len() / 2;
|
||||
let up = keys[mid];
|
||||
let rkeys = keys.split_off(mid + 1);
|
||||
keys.truncate(mid);
|
||||
let rchildren = children.split_off(mid + 1);
|
||||
|
||||
let right_id = self.alloc()?;
|
||||
let mut rp = self.new_page(right_id);
|
||||
write_node(
|
||||
&mut rp,
|
||||
&NodeData::Internal { keys: rkeys, children: rchildren },
|
||||
order,
|
||||
);
|
||||
self.file.write_page(&rp)?;
|
||||
|
||||
self.file.update_page(page_id, |p| {
|
||||
write_node(p, &NodeData::Internal { keys, children }, order)
|
||||
})?;
|
||||
|
||||
Ok((page_id, Some((up, right_id))))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 删掉一个键,键不存在返回 false
|
||||
pub fn delete(&mut self, key: i64) -> io::Result<bool> {
|
||||
match self.root()? {
|
||||
None => Ok(false),
|
||||
Some(r) => self.delete_rec(r, key),
|
||||
}
|
||||
}
|
||||
|
||||
/// 递归删除:一路走到叶子,删掉那一对
|
||||
fn delete_rec(&mut self, page_id: PageId, key: i64) -> io::Result<bool> {
|
||||
let order = self.order;
|
||||
match self.file.with_page(page_id, |p| read_node(p, order))? {
|
||||
NodeData::Leaf { mut keys, mut values, next } => match keys.binary_search(&key) {
|
||||
Err(_) => Ok(false),
|
||||
Ok(i) => {
|
||||
keys.remove(i);
|
||||
values.remove(i);
|
||||
self.file.update_page(page_id, |p| {
|
||||
write_node(p, &NodeData::Leaf { keys, values, next }, order)
|
||||
})?;
|
||||
Ok(true)
|
||||
let id = self.alloc(&node)?;
|
||||
self.set_root(Some(id))
|
||||
}
|
||||
},
|
||||
NodeData::Internal { keys, children } => {
|
||||
let i = child_index(&keys, key);
|
||||
self.delete_rec(children[i], key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 按键升序返回全部
|
||||
pub fn iter_all(&mut self) -> io::Result<Vec<(i64, u64)>> {
|
||||
/// 递归插入,溢出就把右半节点与上提键交给上层
|
||||
fn insert_rec(
|
||||
&mut self,
|
||||
id: PageId,
|
||||
key: &[u8],
|
||||
value: u64,
|
||||
) -> io::Result<Option<(Vec<u8>, 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<bool> {
|
||||
let Some(root) = self.root()? else {
|
||||
return Ok(false);
|
||||
};
|
||||
self.delete_rec(root, key, value)
|
||||
}
|
||||
|
||||
fn delete_rec(&mut self, id: PageId, key: &[u8], value: u64) -> io::Result<bool> {
|
||||
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<Vec<(Vec<u8>, u64)>> {
|
||||
self.scan(None, None)
|
||||
}
|
||||
|
||||
/// 范围扫描:lo / hi 都是闭区间,None 表示这一侧不限
|
||||
pub fn scan(
|
||||
&mut self,
|
||||
lo: Option<&[u8]>,
|
||||
hi: Option<&[u8]>,
|
||||
) -> io::Result<Vec<(Vec<u8>, 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();
|
||||
if let Some(r) = self.root()? {
|
||||
self.walk(r, &mut out)?;
|
||||
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)
|
||||
}
|
||||
|
||||
/// 中序遍历
|
||||
fn walk(&mut self, page_id: PageId, out: &mut Vec<(i64, u64)>) -> io::Result<()> {
|
||||
let order = self.order;
|
||||
match self.file.with_page(page_id, |p| read_node(p, order))? {
|
||||
NodeData::Leaf { keys, values, .. } => {
|
||||
for i in 0..keys.len() {
|
||||
out.push((keys[i], values[i]));
|
||||
}
|
||||
}
|
||||
NodeData::Internal { children, .. } => {
|
||||
for c in children {
|
||||
self.walk(c, out)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 把脏页写回
|
||||
/// 脏页写回
|
||||
pub fn flush(&mut self) -> io::Result<()> {
|
||||
self.file.flush()
|
||||
}
|
||||
|
||||
/// 当前缓存页数
|
||||
pub fn cached_pages(&self) -> usize {
|
||||
self.file.cached_pages()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user