mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-06 00:34:23 +01:00
initial pass at implementing NewRowId
This commit is contained in:
@@ -50,6 +50,10 @@ impl Cursor for PseudoCursor {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn seek_to_last(&mut self) -> Result<CursorResult<()>> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn record(&self) -> Result<Ref<Option<OwnedRecord>>> {
|
||||
Ok(self.current.borrow())
|
||||
}
|
||||
|
||||
@@ -72,6 +72,18 @@ impl BTreeCursor {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_empty_table(&mut self) -> Result<CursorResult<bool>> {
|
||||
let page = self.pager.read_page(self.root_page)?;
|
||||
let page = RefCell::borrow(&page);
|
||||
if page.is_locked() {
|
||||
return Ok(CursorResult::IO);
|
||||
}
|
||||
|
||||
let page = page.contents.read().unwrap();
|
||||
let page = page.as_ref().unwrap();
|
||||
Ok(CursorResult::Ok(page.cell_count() == 0))
|
||||
}
|
||||
|
||||
fn get_next_record(&mut self) -> Result<CursorResult<(Option<u64>, Option<OwnedRecord>)>> {
|
||||
loop {
|
||||
let mem_page = {
|
||||
@@ -184,6 +196,42 @@ impl BTreeCursor {
|
||||
.replace(Some(Rc::new(MemPage::new(None, self.root_page, 0))));
|
||||
}
|
||||
|
||||
fn move_to_rightmost(&mut self) -> Result<CursorResult<()>> {
|
||||
self.move_to_root();
|
||||
|
||||
loop {
|
||||
let mem_page = self.page.borrow().as_ref().unwrap().clone();
|
||||
let page_idx = mem_page.page_idx;
|
||||
let page = self.pager.read_page(page_idx)?;
|
||||
let page = RefCell::borrow(&page);
|
||||
if page.is_locked() {
|
||||
return Ok(CursorResult::IO);
|
||||
}
|
||||
let page = page.contents.read().unwrap();
|
||||
let page = page.as_ref().unwrap();
|
||||
if page.is_leaf() {
|
||||
if page.cell_count() > 0 {
|
||||
mem_page.cell_idx.replace(page.cell_count()-1);
|
||||
}
|
||||
return Ok(CursorResult::Ok(()));
|
||||
}
|
||||
|
||||
match page.rightmost_pointer() {
|
||||
Some(right_most_pointer) => {
|
||||
mem_page.cell_idx.replace(page.cell_count());
|
||||
let mem_page =
|
||||
MemPage::new(Some(mem_page.clone()), right_most_pointer as usize, 0);
|
||||
self.page.replace(Some(Rc::new(mem_page)));
|
||||
continue;
|
||||
},
|
||||
|
||||
None => {
|
||||
unreachable!("interior page should have a rightmost pointer");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_to(&mut self, key: u64) -> Result<CursorResult<()>> {
|
||||
// For a table with N rows, we can find any row by row id in O(log(N)) time by starting at the root page and following the B-tree pointers.
|
||||
// B-trees consist of interior pages and leaf pages. Interior pages contain pointers to other pages, while leaf pages contain the actual row data.
|
||||
@@ -827,6 +875,26 @@ fn find_free_cell(page_ref: &PageContent, db_header: Ref<DatabaseHeader>, amount
|
||||
}
|
||||
|
||||
impl Cursor for BTreeCursor {
|
||||
fn seek_to_last(&mut self) -> Result<CursorResult<()>> {
|
||||
self.move_to_rightmost()?;
|
||||
match self.get_next_record()? {
|
||||
CursorResult::Ok((rowid, next)) => {
|
||||
if rowid.is_none() {
|
||||
match self.is_empty_table()? {
|
||||
CursorResult::Ok(is_empty) => {
|
||||
assert!(is_empty)
|
||||
},
|
||||
CursorResult::IO => (),
|
||||
}
|
||||
}
|
||||
self.rowid.replace(rowid);
|
||||
self.record.replace(next);
|
||||
Ok(CursorResult::Ok(()))
|
||||
}
|
||||
CursorResult::IO => Ok(CursorResult::IO),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.record.borrow().is_none()
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ pub fn translate_insert(
|
||||
},
|
||||
notnull_label,
|
||||
);
|
||||
program.emit_insn(Insn::NewRowid { reg: row_id_reg });
|
||||
program.emit_insn(Insn::NewRowid { cursor: cursor_id, rowid_reg: row_id_reg, prev_largest_reg: 0 });
|
||||
|
||||
program.resolve_label(notnull_label, program.offset());
|
||||
program.emit_insn(Insn::MustBeInt { reg: row_id_reg });
|
||||
|
||||
@@ -370,6 +370,7 @@ pub trait Cursor {
|
||||
fn wait_for_completion(&mut self) -> Result<()>;
|
||||
fn rowid(&self) -> Result<Option<u64>>;
|
||||
fn seek_rowid(&mut self, rowid: u64) -> Result<CursorResult<bool>>;
|
||||
fn seek_to_last(&mut self) -> Result<CursorResult<()>>;
|
||||
fn record(&self) -> Result<Ref<Option<OwnedRecord>>>;
|
||||
fn insert(
|
||||
&mut self,
|
||||
|
||||
@@ -602,11 +602,11 @@ pub fn insn_to_str(
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::NewRowid { reg } => (
|
||||
Insn::NewRowid { cursor, rowid_reg, prev_largest_reg } => (
|
||||
"NewRowId",
|
||||
0,
|
||||
*reg as i32,
|
||||
0,
|
||||
*cursor as i32,
|
||||
*rowid_reg as i32,
|
||||
*prev_largest_reg as i32,
|
||||
OwnedValue::Text(Rc::new("".to_string())),
|
||||
0,
|
||||
"".to_string(),
|
||||
|
||||
@@ -333,7 +333,9 @@ pub enum Insn {
|
||||
},
|
||||
|
||||
NewRowid {
|
||||
reg: usize,
|
||||
cursor: CursorID, // P1
|
||||
rowid_reg: usize, // P2 Destination register to store the new rowid
|
||||
prev_largest_reg: usize // P3 Previous largest rowid in the table (Not used for now)
|
||||
},
|
||||
|
||||
MustBeInt {
|
||||
@@ -1412,7 +1414,16 @@ impl Program {
|
||||
cursor.wait_for_completion()?;
|
||||
state.pc += 1;
|
||||
}
|
||||
Insn::NewRowid { reg: _ } => todo!(),
|
||||
Insn::NewRowid { cursor, rowid_reg, .. } => {
|
||||
let cursor = cursors.get_mut(cursor).unwrap();
|
||||
cursor.seek_to_last()?;
|
||||
if let Some(rowid) = cursor.rowid()? {
|
||||
state.registers[*rowid_reg] = OwnedValue::Integer((rowid+1) as i64);
|
||||
} else {
|
||||
state.registers[*rowid_reg] = OwnedValue::Integer(1);
|
||||
}
|
||||
state.pc += 1;
|
||||
},
|
||||
Insn::MustBeInt { reg } => {
|
||||
match state.registers[*reg] {
|
||||
OwnedValue::Integer(_) => {}
|
||||
|
||||
@@ -79,6 +79,10 @@ impl Cursor for Sorter {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn seek_to_last(&mut self) -> Result<CursorResult<()>> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn record(&self) -> Result<Ref<Option<OwnedRecord>>> {
|
||||
Ok(self.current.borrow())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user