大更新:

1、完善SQL语法
2、移除node前端,只保留静态资源
3、写好安装脚本
4、做好linux适配
This commit is contained in:
LIm1tZz7 committed 2026-10-01 20:48:38 +08:00
1 parent 687c012841
commit df6d348995
166 files changed
+16317 -10763

No files matched your search

+314 -303
View File
@@ -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()
}
}