make find_cell use binary search

This commit is contained in:
Ihor Andrianov
2025-06-28 18:53:44 +03:00
parent a60da8186f
commit 8942bb7474

View File

@@ -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<CursorResult<usize>> {
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<CursorResult<()>> {