From 724bc94f96fc4edebda8eebc9edf678b6cbd7e23 Mon Sep 17 00:00:00 2001 From: Pere Diaz Bou Date: Fri, 24 Oct 2025 13:01:27 +0200 Subject: [PATCH] core/mvcc/cursor: rewind with btree --- core/mvcc/cursor.rs | 101 +++++++++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 38 deletions(-) diff --git a/core/mvcc/cursor.rs b/core/mvcc/cursor.rs index 86b7fd4e4..038ffeb75 100644 --- a/core/mvcc/cursor.rs +++ b/core/mvcc/cursor.rs @@ -131,6 +131,52 @@ impl MvccLazyCursor { fn get_current_pos(&self) -> CursorPosition { *self.current_pos.borrow() } + + /// Returns the new position of the cursor based on the new position in MVCC and the current rowid in BTree. + /// If the new position in MVCC is less than the current rowid in BTree, the cursor will be set to the new position in MVCC. + fn get_new_position_from_mvcc_and_btree( + &mut self, + new_position_in_mvcc: &Option, + current_rowid_in_btree: &Option, + ) -> CursorPosition { + let new_position = match (new_position_in_mvcc, current_rowid_in_btree) { + (Some(mvcc_rowid), Some(btree_rowid)) => { + if mvcc_rowid < btree_rowid { + CursorPosition::Loaded { + row_id: RowID { + table_id: self.table_id, + row_id: *mvcc_rowid, + }, + in_btree: false, + } + } else { + CursorPosition::Loaded { + row_id: RowID { + table_id: self.table_id, + row_id: *btree_rowid, + }, + in_btree: true, + } + } + } + (None, Some(btree_rowid)) => CursorPosition::Loaded { + row_id: RowID { + table_id: self.table_id, + row_id: *btree_rowid, + }, + in_btree: true, + }, + (Some(mvcc_rowid), None) => CursorPosition::Loaded { + row_id: RowID { + table_id: self.table_id, + row_id: *mvcc_rowid, + }, + in_btree: false, + }, + (None, None) => CursorPosition::End, + }; + new_position + } } impl CursorTrait for MvccLazyCursor { @@ -220,42 +266,8 @@ impl CursorTrait for MvccLazyCursor { } else { None }; - let new_position = match (new_position_in_mvcc, current_rowid_in_btree) { - (Some(mvcc_rowid), Some(btree_rowid)) => { - if mvcc_rowid < btree_rowid { - CursorPosition::Loaded { - row_id: RowID { - table_id: self.table_id, - row_id: mvcc_rowid, - }, - in_btree: false, - } - } else { - CursorPosition::Loaded { - row_id: RowID { - table_id: self.table_id, - row_id: btree_rowid, - }, - in_btree: true, - } - } - } - (None, Some(btree_rowid)) => CursorPosition::Loaded { - row_id: RowID { - table_id: self.table_id, - row_id: btree_rowid, - }, - in_btree: true, - }, - (Some(mvcc_rowid), None) => CursorPosition::Loaded { - row_id: RowID { - table_id: self.table_id, - row_id: mvcc_rowid, - }, - in_btree: false, - }, - (None, None) => CursorPosition::End, - }; + let new_position = self + .get_new_position_from_mvcc_and_btree(&new_position_in_mvcc, ¤t_rowid_in_btree); self.current_pos.replace(new_position); self.invalidate_record(); self.state.replace(None); @@ -473,12 +485,25 @@ impl CursorTrait for MvccLazyCursor { } fn rewind(&mut self) -> Result> { + // First run btree_cursor rewind so that we don't need a explicit state machine. + return_if_io!(self.btree_cursor.rewind()); + self.invalidate_record(); if !matches!(self.get_current_pos(), CursorPosition::BeforeFirst) { self.current_pos.replace(CursorPosition::BeforeFirst); } - // Next will set cursor position to a valid position if it exists, otherwise it will set it to one that doesn't exist. - let _ = return_if_io!(self.next()); + + let new_position_in_mvcc = self + .db + .get_next_row_id_for_table(self.table_id, i64::MIN, self.tx_id) + .map(|id| id.row_id); + + let IOResult::Done(maybe_rowid_in_btree) = self.btree_cursor.rowid()? else { + panic!("BTree should have returned rowid after next"); + }; + let new_position = + self.get_new_position_from_mvcc_and_btree(&new_position_in_mvcc, &maybe_rowid_in_btree); + self.current_pos.replace(new_position); Ok(IOResult::Done(())) }