Merge 'core: Clean up B-Tree creation code' from Pekka Enberg

Move page allocation to pager so that we don't need to instantiate a
cursor to create a B-Tree.

Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>

Closes #1093
This commit is contained in:
Pekka Enberg
2025-03-04 19:24:44 +02:00
3 changed files with 36 additions and 34 deletions

View File

@@ -1317,7 +1317,7 @@ impl BTreeCursor {
balance_info.pages_to_balance[i].set_dirty();
pages_to_balance_new.push(balance_info.pages_to_balance[i].clone());
} else {
let page = self.allocate_page(page_type, 0);
let page = self.pager.do_allocate_page(page_type, 0);
pages_to_balance_new.push(page);
// Since this page didn't exist before, we can set it to cells length as it
// marks them as empty since it is a prefix sum of cells.
@@ -1476,7 +1476,7 @@ impl BTreeCursor {
let root = self.stack.top();
let root_contents = root.get_contents();
let child = self.allocate_page(root_contents.page_type(), 0);
let child = self.pager.do_allocate_page(root_contents.page_type(), 0);
tracing::debug!(
"Balancing root. root={}, rightmost={}",
@@ -1533,21 +1533,8 @@ impl BTreeCursor {
self.stack.push(child.clone());
}
/// Allocate a new page to the btree via the pager.
/// This marks the page as dirty and writes the page header.
fn allocate_page(&self, page_type: PageType, offset: usize) -> PageRef {
let page = self.pager.allocate_page().unwrap();
btree_init_page(&page, page_type, offset, self.usable_space() as u16);
page
}
/// The "usable size" of a database page is the page size specified by the 2-byte integer at offset 16
/// in the header, minus the "reserved" space size recorded in the 1-byte integer at offset 20 in the header.
/// The usable size of a page might be an odd number. However, the usable size is not allowed to be less than 480.
/// In other words, if the page size is 512, then the reserved space size cannot exceed 32.
fn usable_space(&self) -> usize {
let db_header = self.pager.db_header.borrow();
(db_header.page_size - db_header.reserved_space as u16) as usize
self.pager.usable_space()
}
/// Find the index of the cell in the page that contains the given rowid.
@@ -1855,20 +1842,6 @@ impl BTreeCursor {
}
}
pub fn btree_create(&mut self, flags: usize) -> u32 {
let page_type = match flags {
1 => PageType::TableLeaf,
2 => PageType::IndexLeaf,
_ => unreachable!(
"wrong create table flags, should be 1 for table and 2 for index, got {}",
flags,
),
};
let page = self.allocate_page(page_type, 0);
let id = page.get().id;
id as u32
}
fn clear_overflow_pages(&self, cell: &BTreeCell) -> Result<CursorResult<()>> {
// Get overflow info based on cell type
let (first_overflow_page, n_overflow) = match cell {

View File

@@ -1,7 +1,7 @@
use crate::result::LimboResult;
use crate::storage::buffer_pool::BufferPool;
use crate::storage::database::DatabaseStorage;
use crate::storage::sqlite3_ondisk::{self, DatabaseHeader, PageContent};
use crate::storage::sqlite3_ondisk::{self, DatabaseHeader, PageContent, PageType};
use crate::storage::wal::{CheckpointResult, Wal};
use crate::{Buffer, LimboError, Result};
use parking_lot::RwLock;
@@ -203,6 +203,37 @@ impl Pager {
})
}
pub fn btree_create(&self, flags: usize) -> u32 {
let page_type = match flags {
1 => PageType::TableLeaf,
2 => PageType::IndexLeaf,
_ => unreachable!(
"wrong create table flags, should be 1 for table and 2 for index, got {}",
flags,
),
};
let page = self.do_allocate_page(page_type, 0);
let id = page.get().id;
id as u32
}
/// Allocate a new page to the btree via the pager.
/// This marks the page as dirty and writes the page header.
pub fn do_allocate_page(&self, page_type: PageType, offset: usize) -> PageRef {
let page = self.allocate_page().unwrap();
crate::btree_init_page(&page, page_type, offset, self.usable_space() as u16);
page
}
/// The "usable size" of a database page is the page size specified by the 2-byte integer at offset 16
/// in the header, minus the "reserved" space size recorded in the 1-byte integer at offset 20 in the header.
/// The usable size of a page might be an odd number. However, the usable size is not allowed to be less than 480.
/// In other words, if the page size is 512, then the reserved space size cannot exceed 32.
pub fn usable_space(&self) -> usize {
let db_header = self.db_header.borrow();
(db_header.page_size - db_header.reserved_space as u16) as usize
}
pub fn begin_read_tx(&self) -> Result<LimboResult> {
self.wal.borrow_mut().begin_read_tx()
}

View File

@@ -2959,9 +2959,7 @@ impl Program {
// TODO: implement temp databases
todo!("temp databases not implemented yet");
}
let mut cursor = Box::new(BTreeCursor::new(pager.clone(), 0));
let root_page = cursor.btree_create(*flags);
let root_page = pager.btree_create(*flags);
state.registers[*root] = OwnedValue::Integer(root_page as i64);
state.pc += 1;
}