Skip to content

(perf): OwnedValue with buffer to reduce allocations in VDBE #1320

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
95 changes: 47 additions & 48 deletions core/storage/btree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ use crate::{
use crate::{
return_corrupt,
types::{
compare_immutable, CursorResult, ImmutableRecord, OwnedValue, RefValue, SeekKey, SeekOp,
compare_immutable, CursorResult, ImmutableRecord, OwnedValue, OwnedValueType, RefValue,
SeekKey, SeekOp,
},
LimboError, Result,
};
Expand Down Expand Up @@ -3546,23 +3547,23 @@ impl BTreeCursor {

pub fn exists(&mut self, key: &OwnedValue) -> Result<CursorResult<bool>> {
assert!(self.mv_cursor.is_none());
let int_key = match key {
OwnedValue::Integer(i) => i,
let int_key = match key.value_type() {
OwnedValueType::Integer => key.as_integer().unwrap(),
_ => unreachable!("btree tables are indexed by integers!"),
};
let _ = return_if_io!(self.move_to(SeekKey::TableRowId(*int_key as u64), SeekOp::EQ));
let _ = return_if_io!(self.move_to(SeekKey::TableRowId(int_key as u64), SeekOp::EQ));
let page = self.stack.top();
// TODO(pere): request load
return_if_locked!(page);

let contents = page.get().contents.as_ref().unwrap();

// find cell
let int_key = match key {
OwnedValue::Integer(i) => *i as u64,
let int_key = match key.value_type() {
OwnedValueType::Integer => key.as_integer().unwrap(),
_ => unreachable!("btree tables are indexed by integers!"),
};
let cell_idx = self.find_cell(contents, &BTreeKey::new_table_rowid(int_key, None));
let cell_idx = self.find_cell(contents, &BTreeKey::new_table_rowid(int_key as u64, None));
if cell_idx >= contents.cell_count() {
Ok(CursorResult::Ok(false))
} else {
Expand All @@ -3572,7 +3573,7 @@ impl BTreeCursor {
payload_overflow_threshold_min(contents.page_type(), self.usable_space() as u16),
self.usable_space(),
)? {
BTreeCell::TableLeafCell(l) => l._rowid == int_key,
BTreeCell::TableLeafCell(l) => l._rowid == int_key as u64,
_ => unreachable!(),
};
Ok(CursorResult::Ok(equals))
Expand Down Expand Up @@ -4966,7 +4967,7 @@ mod tests {
let page = page.get_contents();
let header_size = 8;
let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(1))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(1))]);
let payload = add_record(1, 0, page, record, &conn);
assert_eq!(page.cell_count(), 1);
let free = compute_free_space(page, 4096);
Expand Down Expand Up @@ -4995,7 +4996,7 @@ mod tests {
let usable_space = 4096;
for i in 0..3 {
let record = ImmutableRecord::from_registers(&[Register::OwnedValue(
OwnedValue::Integer(i as i64),
OwnedValue::integer(i as i64),
)]);
let payload = add_record(i, i, page, record, &conn);
assert_eq!(page.cell_count(), i + 1);
Expand Down Expand Up @@ -5248,7 +5249,7 @@ mod tests {
)
.unwrap();
let value = ImmutableRecord::from_registers(&[Register::OwnedValue(
OwnedValue::Blob(vec![0; *size]),
OwnedValue::from_blob(vec![0; *size]),
)]);
tracing::info!("insert key:{}", key);
run_until_done(
Expand Down Expand Up @@ -5329,7 +5330,7 @@ mod tests {
)
.unwrap();
let value = ImmutableRecord::from_registers(&[Register::OwnedValue(
OwnedValue::Blob(vec![0; size]),
OwnedValue::from_blob(vec![0; size]),
)]);
let btree_before = format_btree(pager.clone(), root_page, 0);
run_until_done(
Expand Down Expand Up @@ -5395,7 +5396,7 @@ mod tests {
let total_cells = 10;
for i in 0..total_cells {
let record = ImmutableRecord::from_registers(&[Register::OwnedValue(
OwnedValue::Integer(i as i64),
OwnedValue::integer(i as i64),
)]);
let payload = add_record(i, i, page, record, &conn);
assert_eq!(page.cell_count(), i + 1);
Expand Down Expand Up @@ -5751,7 +5752,7 @@ mod tests {
let usable_space = 4096;
for i in 0..3 {
let record = ImmutableRecord::from_registers(&[Register::OwnedValue(
OwnedValue::Integer(i as i64),
OwnedValue::integer(i as i64),
)]);
let payload = add_record(i, i, page, record, &conn);
assert_eq!(page.cell_count(), i + 1);
Expand Down Expand Up @@ -5793,7 +5794,7 @@ mod tests {
let total_cells = 10;
for i in 0..total_cells {
let record = ImmutableRecord::from_registers(&[Register::OwnedValue(
OwnedValue::Integer(i as i64),
OwnedValue::integer(i as i64),
)]);
let payload = add_record(i, i, page, record, &conn);
assert_eq!(page.cell_count(), i + 1);
Expand Down Expand Up @@ -5849,7 +5850,7 @@ mod tests {
let cell_idx = rng.next_u64() as usize % (page.cell_count() + 1);
let free = compute_free_space(page, usable_space);
let record = ImmutableRecord::from_registers(&[Register::OwnedValue(
OwnedValue::Integer(i as i64),
OwnedValue::integer(i as i64),
)]);
let mut payload: Vec<u8> = Vec::new();
fill_cell_payload(
Expand Down Expand Up @@ -5927,7 +5928,7 @@ mod tests {
let cell_idx = rng.next_u64() as usize % (page.cell_count() + 1);
let free = compute_free_space(page, usable_space);
let record = ImmutableRecord::from_registers(&[Register::OwnedValue(
OwnedValue::Integer(i as i64),
OwnedValue::integer(i as i64),
)]);
let mut payload: Vec<u8> = Vec::new();
fill_cell_payload(
Expand Down Expand Up @@ -6083,7 +6084,7 @@ mod tests {
let usable_space = 4096;

let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(0))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(0))]);
let payload = add_record(0, 0, page, record, &conn);
let free = compute_free_space(page, usable_space);
assert_eq!(free, 4096 - payload.len() as u16 - 2 - header_size);
Expand All @@ -6099,7 +6100,7 @@ mod tests {
let usable_space = 4096;

let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(0))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(0))]);
let payload = add_record(0, 0, page, record, &conn);

assert_eq!(page.cell_count(), 1);
Expand All @@ -6125,8 +6126,8 @@ mod tests {
let usable_space = 4096;

let record = ImmutableRecord::from_registers(&[
Register::OwnedValue(OwnedValue::Integer(0)),
Register::OwnedValue(OwnedValue::Text(Text::new("aaaaaaaa"))),
Register::OwnedValue(OwnedValue::integer(0)),
Register::OwnedValue(OwnedValue::build_text("aaaaaaaa")),
]);
let _ = add_record(0, 0, page, record, &conn);

Expand All @@ -6135,7 +6136,7 @@ mod tests {
assert_eq!(page.cell_count(), 0);

let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(0))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(0))]);
let payload = add_record(0, 0, page, record, &conn);
assert_eq!(page.cell_count(), 1);

Expand All @@ -6159,8 +6160,8 @@ mod tests {
let usable_space = 4096;

let record = ImmutableRecord::from_registers(&[
Register::OwnedValue(OwnedValue::Integer(0)),
Register::OwnedValue(OwnedValue::Text(Text::new("aaaaaaaa"))),
Register::OwnedValue(OwnedValue::integer(0)),
Register::OwnedValue(OwnedValue::build_text("aaaaaaaa")),
]);
let _ = add_record(0, 0, page, record, &conn);

Expand All @@ -6170,7 +6171,7 @@ mod tests {
assert_eq!(page.cell_count(), 0);

let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(0))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(0))]);
let payload = add_record(0, 0, page, record, &conn);
assert_eq!(page.cell_count(), 1);

Expand All @@ -6195,13 +6196,13 @@ mod tests {
let usable_space = 4096;

let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(0))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(0))]);
let payload = add_record(0, 0, page, record, &conn);
let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(1))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(1))]);
let _ = add_record(1, 1, page, record, &conn);
let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(2))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(2))]);
let _ = add_record(2, 2, page, record, &conn);

drop_cell(page, 1, usable_space).unwrap();
Expand All @@ -6220,24 +6221,24 @@ mod tests {
let usable_space = 4096;

let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(0))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(0))]);
let _ = add_record(0, 0, page, record, &conn);

let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(0))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(0))]);
let _ = add_record(0, 0, page, record, &conn);
drop_cell(page, 0, usable_space).unwrap();

defragment_page(page, usable_space);

let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(0))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(0))]);
let _ = add_record(0, 1, page, record, &conn);

drop_cell(page, 0, usable_space).unwrap();

let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(0))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(0))]);
let _ = add_record(0, 1, page, record, &conn);
}

Expand All @@ -6250,7 +6251,7 @@ mod tests {
let usable_space = 4096;
let insert = |pos, page| {
let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(0))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(0))]);
let _ = add_record(0, pos, page, record, &conn);
};
let drop = |pos, page| {
Expand Down Expand Up @@ -6290,7 +6291,7 @@ mod tests {
let usable_space = 4096;
let insert = |pos, page| {
let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(0))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(0))]);
let _ = add_record(0, pos, page, record, &conn);
};
let drop = |pos, page| {
Expand All @@ -6300,7 +6301,7 @@ mod tests {
defragment_page(page, usable_space);
};
let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(0))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(0))]);
let mut payload: Vec<u8> = Vec::new();
fill_cell_payload(
page.get_contents().page_type(),
Expand Down Expand Up @@ -6334,7 +6335,7 @@ mod tests {
let mut cursor = BTreeCursor::new(None, pager.clone(), root_page);
tracing::info!("INSERT INTO t VALUES ({});", i,);
let value =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Integer(i))]);
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::integer(i))]);
tracing::trace!("before insert {}", i);
run_until_done(
|| {
Expand All @@ -6360,7 +6361,7 @@ mod tests {
);
for key in keys.iter() {
let mut cursor = BTreeCursor::new(None, pager.clone(), root_page);
let key = OwnedValue::Integer(*key);
let key = OwnedValue::integer(*key);
let exists = run_until_done(|| cursor.exists(&key), pager.deref()).unwrap();
assert!(exists, "key not found {}", key);
}
Expand All @@ -6374,7 +6375,7 @@ mod tests {
let page = get_page(2);
let usable_space = 4096;
let record =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Blob(vec![
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::from_blob(vec![
0;
3600
]))]);
Expand Down Expand Up @@ -6412,9 +6413,9 @@ mod tests {
// Insert 10,000 records in to the BTree.
for i in 1..=10000 {
let mut cursor = BTreeCursor::new(None, pager.clone(), root_page);
let value = ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Text(
Text::new("hello world"),
))]);
let value = ImmutableRecord::from_registers(&[Register::OwnedValue(
OwnedValue::build_text("hello world"),
)]);

run_until_done(
|| {
Expand Down Expand Up @@ -6457,15 +6458,15 @@ mod tests {
}

let mut cursor = BTreeCursor::new(None, pager.clone(), root_page);
let key = OwnedValue::Integer(i);
let key = OwnedValue::integer(i);
let exists = run_until_done(|| cursor.exists(&key), pager.deref()).unwrap();
assert!(exists, "Key {} should exist but doesn't", i);
}

// Verify the deleted records don't exist.
for i in 500..=3500 {
let mut cursor = BTreeCursor::new(None, pager.clone(), root_page);
let key = OwnedValue::Integer(i);
let key = OwnedValue::integer(i);
let exists = run_until_done(|| cursor.exists(&key), pager.deref()).unwrap();
assert!(!exists, "Deleted key {} still exists", i);
}
Expand All @@ -6488,11 +6489,9 @@ mod tests {
for i in 0..iterations {
let mut cursor = BTreeCursor::new(None, pager.clone(), root_page);
tracing::info!("INSERT INTO t VALUES ({});", i,);
let value =
ImmutableRecord::from_registers(&[Register::OwnedValue(OwnedValue::Text(Text {
value: huge_texts[i].as_bytes().to_vec(),
subtype: crate::types::TextSubtype::Text,
}))]);
let value = ImmutableRecord::from_registers(&[Register::OwnedValue(
OwnedValue::build_text(huge_texts[i].as_str()),
)]);
tracing::trace!("before insert {}", i);
tracing::debug!(
"=========== btree before ===========\n{}\n\n",
Expand Down
50 changes: 25 additions & 25 deletions core/storage/sqlite3_ondisk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1645,32 +1645,32 @@ mod tests {
use rstest::rstest;

#[rstest]
#[case(&[], SERIAL_TYPE_NULL, OwnedValue::Null)]
#[case(&[255], SERIAL_TYPE_INT8, OwnedValue::Integer(-1))]
#[case(&[0x12, 0x34], SERIAL_TYPE_BEINT16, OwnedValue::Integer(0x1234))]
#[case(&[0xFE], SERIAL_TYPE_INT8, OwnedValue::Integer(-2))]
#[case(&[0x12, 0x34, 0x56], SERIAL_TYPE_BEINT24, OwnedValue::Integer(0x123456))]
#[case(&[0x12, 0x34, 0x56, 0x78], SERIAL_TYPE_BEINT32, OwnedValue::Integer(0x12345678))]
#[case(&[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC], SERIAL_TYPE_BEINT48, OwnedValue::Integer(0x123456789ABC))]
#[case(&[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF], SERIAL_TYPE_BEINT64, OwnedValue::Integer(0x123456789ABCDEFF))]
#[case(&[0x40, 0x09, 0x21, 0xFB, 0x54, 0x44, 0x2D, 0x18], SERIAL_TYPE_BEFLOAT64, OwnedValue::Float(std::f64::consts::PI))]
#[case(&[1, 2], SERIAL_TYPE_CONSTINT0, OwnedValue::Integer(0))]
#[case(&[65, 66], SERIAL_TYPE_CONSTINT1, OwnedValue::Integer(1))]
#[case(&[1, 2, 3], 18, OwnedValue::Blob(vec![1, 2, 3].into()))]
#[case(&[], 12, OwnedValue::Blob(vec![].into()))] // empty blob
#[case(&[], SERIAL_TYPE_NULL, OwnedValue::null())]
#[case(&[255], SERIAL_TYPE_INT8, OwnedValue::integer(-1))]
#[case(&[0x12, 0x34], SERIAL_TYPE_BEINT16, OwnedValue::integer(0x1234))]
#[case(&[0xFE], SERIAL_TYPE_INT8, OwnedValue::integer(-2))]
#[case(&[0x12, 0x34, 0x56], SERIAL_TYPE_BEINT24, OwnedValue::integer(0x123456))]
#[case(&[0x12, 0x34, 0x56, 0x78], SERIAL_TYPE_BEINT32, OwnedValue::integer(0x12345678))]
#[case(&[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC], SERIAL_TYPE_BEINT48, OwnedValue::integer(0x123456789ABC))]
#[case(&[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF], SERIAL_TYPE_BEINT64, OwnedValue::integer(0x123456789ABCDEFF))]
#[case(&[0x40, 0x09, 0x21, 0xFB, 0x54, 0x44, 0x2D, 0x18], SERIAL_TYPE_BEFLOAT64, OwnedValue::float(std::f64::consts::PI))]
#[case(&[1, 2], SERIAL_TYPE_CONSTINT0, OwnedValue::integer(0))]
#[case(&[65, 66], SERIAL_TYPE_CONSTINT1, OwnedValue::integer(1))]
#[case(&[1, 2, 3], 18, OwnedValue::from_blob(vec![1, 2, 3].into()))]
#[case(&[], 12, OwnedValue::from_blob(vec![].into()))] // empty blob
#[case(&[65, 66, 67], 19, OwnedValue::build_text("ABC"))]
#[case(&[0x80], SERIAL_TYPE_INT8, OwnedValue::Integer(-128))]
#[case(&[0x80, 0], SERIAL_TYPE_BEINT16, OwnedValue::Integer(-32768))]
#[case(&[0x80, 0, 0], SERIAL_TYPE_BEINT24, OwnedValue::Integer(-8388608))]
#[case(&[0x80, 0, 0, 0], SERIAL_TYPE_BEINT32, OwnedValue::Integer(-2147483648))]
#[case(&[0x80, 0, 0, 0, 0, 0], SERIAL_TYPE_BEINT48, OwnedValue::Integer(-140737488355328))]
#[case(&[0x80, 0, 0, 0, 0, 0, 0, 0], SERIAL_TYPE_BEINT64, OwnedValue::Integer(-9223372036854775808))]
#[case(&[0x7f], SERIAL_TYPE_INT8, OwnedValue::Integer(127))]
#[case(&[0x7f, 0xff], SERIAL_TYPE_BEINT16, OwnedValue::Integer(32767))]
#[case(&[0x7f, 0xff, 0xff], SERIAL_TYPE_BEINT24, OwnedValue::Integer(8388607))]
#[case(&[0x7f, 0xff, 0xff, 0xff], SERIAL_TYPE_BEINT32, OwnedValue::Integer(2147483647))]
#[case(&[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff], SERIAL_TYPE_BEINT48, OwnedValue::Integer(140737488355327))]
#[case(&[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], SERIAL_TYPE_BEINT64, OwnedValue::Integer(9223372036854775807))]
#[case(&[0x80], SERIAL_TYPE_INT8, OwnedValue::integer(-128))]
#[case(&[0x80, 0], SERIAL_TYPE_BEINT16, OwnedValue::integer(-32768))]
#[case(&[0x80, 0, 0], SERIAL_TYPE_BEINT24, OwnedValue::integer(-8388608))]
#[case(&[0x80, 0, 0, 0], SERIAL_TYPE_BEINT32, OwnedValue::integer(-2147483648))]
#[case(&[0x80, 0, 0, 0, 0, 0], SERIAL_TYPE_BEINT48, OwnedValue::integer(-140737488355328))]
#[case(&[0x80, 0, 0, 0, 0, 0, 0, 0], SERIAL_TYPE_BEINT64, OwnedValue::integer(-9223372036854775808))]
#[case(&[0x7f], SERIAL_TYPE_INT8, OwnedValue::integer(127))]
#[case(&[0x7f, 0xff], SERIAL_TYPE_BEINT16, OwnedValue::integer(32767))]
#[case(&[0x7f, 0xff, 0xff], SERIAL_TYPE_BEINT24, OwnedValue::integer(8388607))]
#[case(&[0x7f, 0xff, 0xff, 0xff], SERIAL_TYPE_BEINT32, OwnedValue::integer(2147483647))]
#[case(&[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff], SERIAL_TYPE_BEINT48, OwnedValue::integer(140737488355327))]
#[case(&[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], SERIAL_TYPE_BEINT64, OwnedValue::integer(9223372036854775807))]
fn test_read_value(
#[case] buf: &[u8],
#[case] serial_type: SerialType,
Expand Down
Loading
Loading