diff --git a/Cargo.lock b/Cargo.lock index f25ad611d..e64dc3c1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -736,6 +736,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", + "regex", ] [[package]] @@ -767,7 +768,10 @@ version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" dependencies = [ + "anstream", + "anstyle", "env_filter", + "humantime", "log", ] @@ -1612,6 +1616,7 @@ dependencies = [ "chrono", "criterion", "crossbeam-skiplist", + "env_logger 0.11.6", "fallible-iterator 0.3.0", "getrandom 0.2.15", "hex", diff --git a/core/Cargo.toml b/core/Cargo.toml index 58a29c475..6799fe29b 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -96,6 +96,7 @@ quickcheck = { version = "1.0", default-features = false } quickcheck_macros = { version = "1.0", default-features = false } rand = "0.8.5" # Required for quickcheck rand_chacha = "0.9.0" +env_logger = "0.11.6" [[bench]] name = "benchmark" diff --git a/core/storage/btree.rs b/core/storage/btree.rs index 280f46eac..efdcb47ae 100644 --- a/core/storage/btree.rs +++ b/core/storage/btree.rs @@ -2375,6 +2375,65 @@ mod tests { use std::cell::RefCell; use std::sync::Arc; + fn format_btree(pager: Rc, page_idx: usize, depth: usize) -> String { + let cursor = BTreeCursor::new(pager.clone(), page_idx); + let page = pager.read_page(page_idx).unwrap(); + let page = page.get(); + let contents = page.contents.as_ref().unwrap(); + let page_type = contents.page_type(); + let mut current = Vec::new(); + let mut child = Vec::new(); + for cell_idx in 0..contents.cell_count() { + let cell = contents + .cell_get( + cell_idx, + pager.clone(), + cursor.payload_overflow_threshold_max(page_type), + cursor.payload_overflow_threshold_min(page_type), + cursor.usable_space(), + ) + .unwrap(); + match cell { + BTreeCell::TableInteriorCell(cell) => { + current.push(format!( + "node[rowid:{}, ptr(<=):{}]", + cell._rowid, cell._left_child_page + )); + child.push(format_btree( + pager.clone(), + cell._left_child_page as usize, + depth + 2, + )); + } + BTreeCell::TableLeafCell(cell) => { + current.push(format!( + "leaf[rowid:{}, len(payload):{}, overflow:{}]", + cell._rowid, + cell._payload.len(), + cell.first_overflow_page.is_some() + )); + } + _ => panic!("unsupported btree cell: {:?}", cell), + } + } + if let Some(rightmost) = contents.rightmost_pointer() { + child.push(format_btree(pager.clone(), rightmost as usize, depth + 2)); + } + let current = format!( + "{}-page:{}, ptr(right):{}\n{}+cells:{}", + " ".repeat(depth), + page_idx, + contents.rightmost_pointer().unwrap_or(0), + " ".repeat(depth), + current.join(", ") + ); + if child.is_empty() { + current + } else { + current + "\n" + &child.join("\n") + } + } + fn empty_btree() -> (Rc, usize) { let db_header = DatabaseHeader::default(); let page_size = db_header.page_size as usize; @@ -2401,30 +2460,35 @@ mod tests { #[test] pub fn btree_insert_fuzz() { + let _ = env_logger::init(); let (pager, root_page) = empty_btree(); - let mut cursor = BTreeCursor::new(pager, root_page); + let mut cursor = BTreeCursor::new(pager.clone(), root_page); let mut keys = Vec::new(); let mut rng = ChaCha8Rng::seed_from_u64(0); for _ in 0..16 { let size = (rng.next_u64() % 4096) as usize; let key = (rng.next_u64() % (1 << 30)) as i64; keys.push(key); - println!("INSERT INTO t VALUES ({}, randomblob({}));", key, size); + log::info!("INSERT INTO t VALUES ({}, randomblob({}));", key, size); let key = OwnedValue::Integer(key); let value = Record::new(vec![OwnedValue::Blob(Rc::new(vec![0; size]))]); cursor.insert(&key, &value, false).unwrap(); - } - - for key in keys { - let seek_key = SeekKey::TableRowId(key as u64); - assert!( - matches!( - cursor.seek(seek_key, SeekOp::EQ).unwrap(), - CursorResult::Ok(true) - ), - "key {} is not found", - key + log::info!( + "=========== btree ===========\n{}\n\n", + format_btree(pager.clone(), root_page, 0) ); + + for key in keys.iter() { + let seek_key = SeekKey::TableRowId(*key as u64); + assert!( + matches!( + cursor.seek(seek_key, SeekOp::EQ).unwrap(), + CursorResult::Ok(true) + ), + "key {} is not found", + key + ); + } } } diff --git a/core/storage/sqlite3_ondisk.rs b/core/storage/sqlite3_ondisk.rs index 4963fa669..fbdac7dca 100644 --- a/core/storage/sqlite3_ondisk.rs +++ b/core/storage/sqlite3_ondisk.rs @@ -362,7 +362,7 @@ pub fn write_header_to_buf(buf: &mut [u8], header: &DatabaseHeader) { } #[repr(u8)] -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, Copy)] pub enum PageType { IndexInterior = 2, TableInterior = 5,