diff --git a/core/storage/btree.rs b/core/storage/btree.rs index 08f7e9a33..a2590df05 100644 --- a/core/storage/btree.rs +++ b/core/storage/btree.rs @@ -3846,30 +3846,42 @@ impl BTreeCursor { /// Find the index of the cell in the page that contains the given rowid. fn find_cell(&mut self, page: &PageContent, key: &BTreeKey) -> Result> { - if self.find_cell_state.0.is_none() { - self.find_cell_state.set(0); - } let cell_count = page.cell_count(); - while self.find_cell_state.get_cell_idx() < cell_count as isize { - assert!(self.find_cell_state.get_cell_idx() >= 0); - let cell_idx = self.find_cell_state.get_cell_idx() as usize; - match page - .cell_get( - cell_idx, - payload_overflow_threshold_max(page.page_type(), self.usable_space() as u16), - payload_overflow_threshold_min(page.page_type(), self.usable_space() as u16), - self.usable_space(), - ) - .unwrap() - { + let mut low = 0; + let mut high = if cell_count > 0 { cell_count - 1 } else { 0 }; + let mut result_index = cell_count; + + if self.find_cell_state.0.is_some() { + low = self.find_cell_state.get_cell_idx() as usize; + } + + while low <= high && cell_count > 0 { + let mid = low + (high - low) / 2; + self.find_cell_state.set(mid as isize); + + let cell = match page.cell_get( + mid, + payload_overflow_threshold_max(page.page_type(), self.usable_space() as u16), + payload_overflow_threshold_min(page.page_type(), self.usable_space() as u16), + self.usable_space(), + ) { + Ok(c) => c, + Err(e) => return Err(e), + }; + + let comparison_result = match cell { BTreeCell::TableLeafCell(cell) => { if key.to_rowid() <= cell._rowid { - break; + Ordering::Less + } else { + Ordering::Greater } } BTreeCell::TableInteriorCell(cell) => { if key.to_rowid() <= cell._rowid { - break; + Ordering::Less + } else { + Ordering::Greater } } BTreeCell::IndexInteriorCell(IndexInteriorCell { @@ -3882,41 +3894,44 @@ impl BTreeCursor { payload, first_overflow_page, payload_size, + .. }) => { // TODO: implement efficient comparison of records // e.g. https://github.com/sqlite/sqlite/blob/master/src/vdbeaux.c#L4719 return_if_io!(self.read_record_w_possible_overflow( payload, first_overflow_page, - payload_size, + payload_size )); + let key_values = key.to_index_key_values(); let record = self.get_immutable_record(); let record = record.as_ref().unwrap(); let record_same_number_cols = &record.get_values()[..key_values.len()]; - let order = compare_immutable( + compare_immutable( key_values, record_same_number_cols, self.key_sort_order(), &self.collations, - ); - match order { - Ordering::Less | Ordering::Equal => { - break; - } - Ordering::Greater => {} - } + ) } + }; + + if comparison_result == Ordering::Greater { + low = mid + 1; + } else { + result_index = mid; + if mid == 0 { + break; + } + high = mid - 1; } - let cell_idx = self.find_cell_state.get_cell_idx(); - self.find_cell_state.set(cell_idx + 1); } - let cell_idx = self.find_cell_state.get_cell_idx(); - assert!(cell_idx >= 0); - let cell_idx = cell_idx as usize; - assert!(cell_idx <= cell_count); + self.find_cell_state.reset(); - Ok(CursorResult::Ok(cell_idx)) + assert!(result_index <= cell_count); + + Ok(CursorResult::Ok(result_index)) } pub fn seek_end(&mut self) -> Result> {