144 lines
4.2 KiB
Rust
144 lines
4.2 KiB
Rust
use chusql_storage::config::DEFAULT_PAGE_SIZE;
|
|
use chusql_storage::heap::HeapTable;
|
|
use chusql_storage::page::DEFAULT_POOL_SIZE;
|
|
use chusql_storage::protocol::Row;
|
|
use serde_json::json;
|
|
|
|
// 堆表测试:插查、跨页、大行、重开、索引重建。
|
|
|
|
fn row(pairs: &[(&str, serde_json::Value)]) -> Row {
|
|
let mut m = Row::new();
|
|
for (k, v) in pairs {
|
|
m.insert((*k).to_string(), v.clone());
|
|
}
|
|
m
|
|
}
|
|
|
|
/// 插一行再扫描读回
|
|
#[test]
|
|
fn insert_and_scan_one_row() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("t.db");
|
|
let mut t = HeapTable::open(&path, DEFAULT_PAGE_SIZE, DEFAULT_POOL_SIZE).unwrap();
|
|
|
|
t.insert(&row(&[("id", json!(1)), ("name", json!("Alice"))]))
|
|
.unwrap();
|
|
|
|
let rows = t.scan().unwrap();
|
|
assert_eq!(rows.len(), 1);
|
|
assert_eq!(rows[0]["id"], json!(1));
|
|
assert_eq!(rows[0]["name"], json!("Alice"));
|
|
}
|
|
|
|
/// 500 行跨页顺序不变
|
|
#[test]
|
|
fn insert_many_rows_cross_pages() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("t.db");
|
|
let mut t = HeapTable::open(&path, DEFAULT_PAGE_SIZE, DEFAULT_POOL_SIZE).unwrap();
|
|
|
|
for i in 0..500 {
|
|
t.insert(&row(&[("id", json!(i))])).unwrap();
|
|
}
|
|
|
|
let rows = t.scan().unwrap();
|
|
assert_eq!(rows.len(), 500);
|
|
for (i, r) in rows.iter().enumerate() {
|
|
assert_eq!(r["id"], json!(i as i64));
|
|
}
|
|
}
|
|
|
|
/// 2KB 大行放得下
|
|
#[test]
|
|
fn large_row_still_fits() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("t.db");
|
|
let mut t = HeapTable::open(&path, DEFAULT_PAGE_SIZE, DEFAULT_POOL_SIZE).unwrap();
|
|
|
|
let big = "x".repeat(2000);
|
|
t.insert(&row(&[("data", json!(big.clone()))])).unwrap();
|
|
|
|
let rows = t.scan().unwrap();
|
|
assert_eq!(rows.len(), 1);
|
|
assert_eq!(rows[0]["data"], json!(big));
|
|
}
|
|
|
|
/// 超页的行要报错
|
|
#[test]
|
|
fn row_too_large_errors() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("t.db");
|
|
let mut t = HeapTable::open(&path, DEFAULT_PAGE_SIZE, DEFAULT_POOL_SIZE).unwrap();
|
|
|
|
let huge = "x".repeat(10_000);
|
|
let err = t.insert(&row(&[("data", json!(huge))]));
|
|
assert!(err.is_err());
|
|
}
|
|
|
|
/// 重开文件数据还在
|
|
#[test]
|
|
fn reopen_and_scan() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("t.db");
|
|
|
|
{
|
|
let mut t = HeapTable::open(&path, DEFAULT_PAGE_SIZE, DEFAULT_POOL_SIZE).unwrap();
|
|
t.insert(&row(&[("id", json!(1))])).unwrap();
|
|
t.insert(&row(&[("id", json!(2))])).unwrap();
|
|
}
|
|
|
|
let mut t = HeapTable::open(&path, DEFAULT_PAGE_SIZE, DEFAULT_POOL_SIZE).unwrap();
|
|
let rows = t.scan().unwrap();
|
|
assert_eq!(rows.len(), 2);
|
|
assert_eq!(rows[0]["id"], json!(1));
|
|
assert_eq!(rows[1]["id"], json!(2));
|
|
}
|
|
|
|
/// 512 字节页可用
|
|
#[test]
|
|
fn custom_page_size() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("small.db");
|
|
let mut t = HeapTable::open(&path, 512, DEFAULT_POOL_SIZE).unwrap();
|
|
|
|
for i in 0..50 {
|
|
t.insert(&row(&[("id", json!(i))])).unwrap();
|
|
}
|
|
assert_eq!(t.scan().unwrap().len(), 50);
|
|
|
|
let big = "x".repeat(600);
|
|
assert!(t.insert(&row(&[("data", json!(big))])).is_err());
|
|
}
|
|
|
|
/// 整表改写后索引重建
|
|
#[test]
|
|
fn replace_all_rebuilds_index() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let mut t = HeapTable::open_indexed(
|
|
dir.path().join("t.db"),
|
|
dir.path().join("t.idx"),
|
|
DEFAULT_PAGE_SIZE,
|
|
chusql_storage::config::DEFAULT_BTREE_ORDER,
|
|
DEFAULT_POOL_SIZE,
|
|
)
|
|
.unwrap();
|
|
|
|
t.insert_keyed(&row(&[("id", json!(1)), ("name", json!("Alice"))]), 1)
|
|
.unwrap();
|
|
t.insert_keyed(&row(&[("id", json!(2)), ("name", json!("Bob"))]), 2)
|
|
.unwrap();
|
|
assert!(t.get_by_key(1).unwrap().is_some());
|
|
|
|
t.replace_all(&[
|
|
row(&[("id", json!(7)), ("name", json!("Zoe"))]),
|
|
row(&[("name", json!("NoId"))]),
|
|
])
|
|
.unwrap();
|
|
|
|
assert!(t.get_by_key(1).unwrap().is_none(), "旧键必须作废");
|
|
assert!(t.get_by_key(2).unwrap().is_none());
|
|
let got = t.get_by_key(7).unwrap().expect("新行应该按 id 建好索引");
|
|
assert_eq!(got["name"], json!("Zoe"));
|
|
assert_eq!(t.scan().unwrap().len(), 2);
|
|
}
|