Merge 'Fix btree balance and seek after overwritten cell overflows' from Jussi Saurio

Closes #1809
Closes #1810
Closes #1811
Closes #1812
Closes #1813
Closes #1814
Closes #1815
and probably Closes #1805

Reviewed-by: Pere Diaz Bou <pere-altea@homail.com>

Closes #1816
This commit is contained in:
Jussi Saurio
2025-06-24 13:29:53 +03:00
2 changed files with 40 additions and 16 deletions

View File

@@ -2128,12 +2128,21 @@ impl BTreeCursor {
match cell {
BTreeCell::TableLeafCell(tbl_leaf) => {
if tbl_leaf._rowid == bkey.to_rowid() {
tracing::debug!("found exact match with cell_idx={cell_idx}, overwriting");
tracing::debug!("TableLeafCell: found exact match with cell_idx={cell_idx}, overwriting");
self.overwrite_cell(page.clone(), cell_idx, record)?;
self.state
let write_info = self
.state
.mut_write_info()
.expect("expected write info")
.state = WriteState::Finish;
.expect("expected write info");
if page.get().get_contents().overflow_cells.is_empty() {
write_info.state = WriteState::Finish;
} else {
write_info.state = WriteState::BalanceStart;
// If we balance, we must save the cursor position and seek to it later.
// FIXME: we shouldn't have both DeleteState::SeekAfterBalancing and
// save_context()/restore/context(), they are practically the same thing.
self.save_context(CursorContext::TableRowId(bkey.to_rowid()));
}
continue;
}
}
@@ -2149,13 +2158,22 @@ impl BTreeCursor {
&self.collations,
);
if cmp == Ordering::Equal {
tracing::debug!("found exact match with cell_idx={cell_idx}, overwriting");
tracing::debug!("IndexLeafCell: found exact match with cell_idx={cell_idx}, overwriting");
self.has_record.set(true);
self.overwrite_cell(page.clone(), cell_idx, record)?;
self.state
let write_info = self
.state
.mut_write_info()
.expect("expected write info")
.state = WriteState::Finish;
.expect("expected write info");
if page.get().get_contents().overflow_cells.is_empty() {
write_info.state = WriteState::Finish;
} else {
write_info.state = WriteState::BalanceStart;
// If we balance, we must save the cursor position and seek to it later.
// FIXME: we shouldn't have both DeleteState::SeekAfterBalancing and
// save_context()/restore/context(), they are practically the same thing.
self.save_context(CursorContext::IndexKeyRowId((*record).clone()));
}
continue;
}
}
@@ -4023,7 +4041,10 @@ impl BTreeCursor {
_rowid, _payload, ..
}) = cell
else {
unreachable!("unexpected page_type");
unreachable!(
"BTreeCursor::rowid(): unexpected page_type: {:?}",
page_type
);
};
Ok(CursorResult::Ok(Some(_rowid)))
} else {

View File

@@ -485,14 +485,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
_ => panic!("Error executing query: {}", e),
}
}
let mut res = conn.query("PRAGMA integrity_check", ()).await.unwrap();
if let Some(row) = res.next().await? {
let value = row.get_value(0).unwrap();
if value != "ok".into() {
panic!("integrity check failed: {:?}", value);
const INTEGRITY_CHECK_INTERVAL: usize = 100;
if query_index % INTEGRITY_CHECK_INTERVAL == 0 {
let mut res = conn.query("PRAGMA integrity_check", ()).await.unwrap();
if let Some(row) = res.next().await? {
let value = row.get_value(0).unwrap();
if value != "ok".into() {
panic!("integrity check failed: {:?}", value);
}
} else {
panic!("integrity check failed: no rows");
}
} else {
panic!("integrity check failed: no rows");
}
}
Ok::<_, Box<dyn std::error::Error + Send + Sync>>(())