Skip to content

Commit

Permalink
Add AlgebraicValue::take + move test-code in btree_index to tests (
Browse files Browse the repository at this point in the history
…#1028)

* add AlgebraicValue::take for a neater interface

* btree_index: move test-only code to tests
  • Loading branch information
Centril authored Mar 27, 2024
1 parent 99bd7ac commit b6c0e1c
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 26 deletions.
8 changes: 7 additions & 1 deletion crates/sats/src/algebraic_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ pub mod de;
pub mod ser;

use crate::{AlgebraicType, ArrayValue, MapValue, ProductValue, SumValue};
use core::mem;
use core::ops::{Bound, RangeBounds};
use derive_more::From;
use enum_as_inner::EnumAsInner;
use std::ops::{Bound, RangeBounds};

/// Totally ordered [`f32`] allowing all IEEE-754 floating point values.
pub type F32 = decorum::Total<f32>;
Expand Down Expand Up @@ -112,6 +113,11 @@ pub enum AlgebraicValue {

#[allow(non_snake_case)]
impl AlgebraicValue {
/// Extract the value and replace it with a dummy one that is cheap to make.
pub fn take(&mut self) -> Self {
mem::replace(self, Self::U8(0))
}

/// Interpret the value as a byte slice or `None` if it isn't a byte slice.
#[inline]
pub fn as_bytes(&self) -> Option<&[u8]> {
Expand Down
36 changes: 16 additions & 20 deletions crates/table/src/btree_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::{
use core::ops::RangeBounds;
use multimap::{MultiMap, MultiMapRangeIter};
use spacetimedb_primitives::{ColList, IndexId};
use spacetimedb_sats::{product_value::InvalidFieldError, AlgebraicValue, ProductValue};
use spacetimedb_sats::{product_value::InvalidFieldError, AlgebraicValue};

mod multimap;

Expand Down Expand Up @@ -375,11 +375,6 @@ impl BTreeIndex {
})
}

/// Extracts from `row` the relevant column values according to what columns are indexed.
pub fn get_fields(&self, cols: &ColList, row: &ProductValue) -> Result<AlgebraicValue, InvalidFieldError> {
row.project_not_empty(cols)
}

/// Inserts `ptr` with the value `row` to this index.
/// This index will extract the necessary values from `row` based on `self.cols`.
///
Expand All @@ -395,15 +390,6 @@ impl BTreeIndex {
self.idx.delete(cols, row_ref)
}

/// Returns whether indexing `row` again would violate a unique constraint, if any.
pub fn violates_unique_constraint(&self, cols: &ColList, row: &ProductValue) -> bool {
if self.is_unique {
let col_value = self.get_fields(cols, row).unwrap();
return self.contains_any(&col_value);
}
false
}

/// Returns an iterator over the rows that would violate the unique constraint of this index,
/// if `row` were inserted,
/// or `None`, if this index doesn't have a unique constraint.
Expand Down Expand Up @@ -467,7 +453,7 @@ mod test {
use spacetimedb_primitives::ColListBuilder;
use spacetimedb_sats::{
db::def::{TableDef, TableSchema},
product, AlgebraicType, ProductType,
product, AlgebraicType, ProductType, ProductValue,
};
use std::collections::HashMap;

Expand Down Expand Up @@ -497,6 +483,16 @@ mod test {
Table::new(schema, SquashedOffset::COMMITTED_STATE)
}

/// Extracts from `row` the relevant column values according to what columns are indexed.
fn get_fields(cols: &ColList, row: &ProductValue) -> AlgebraicValue {
row.project_not_empty(cols).unwrap()
}

/// Returns whether indexing `row` again would violate a unique constraint, if any.
fn violates_unique_constraint(index: &BTreeIndex, cols: &ColList, row: &ProductValue) -> bool {
!index.is_unique || index.contains_any(&get_fields(cols, row))
}

proptest! {
#[test]
fn remove_nonexistent_noop(((ty, cols, pv), is_unique) in (gen_row_and_cols(), any::<bool>())) {
Expand All @@ -516,7 +512,7 @@ mod test {
let mut blob_store = HashMapBlobStore::default();
let ptr = table.insert(&mut blob_store, &pv).unwrap().1;
let row_ref = table.get_row_ref(&blob_store, ptr).unwrap();
let value = index.get_fields(&cols, &pv).unwrap();
let value = get_fields(&cols, &pv);

prop_assert_eq!(index.idx.len(), 0);
prop_assert_eq!(index.contains_any(&value), false);
Expand All @@ -541,11 +537,11 @@ mod test {
let mut blob_store = HashMapBlobStore::default();
let ptr = table.insert(&mut blob_store, &pv).unwrap().1;
let row_ref = table.get_row_ref(&blob_store, ptr).unwrap();
let value = index.get_fields(&cols, &pv).unwrap();
let value = get_fields(&cols, &pv);

// Nothing in the index yet.
prop_assert_eq!(index.idx.len(), 0);
prop_assert_eq!(index.violates_unique_constraint(&cols, &pv), false);
prop_assert_eq!(violates_unique_constraint(&index, &cols, &pv), false);
prop_assert_eq!(
index.get_rows_that_violate_unique_constraint(&value).unwrap().collect::<Vec<_>>(),
[]
Expand All @@ -556,7 +552,7 @@ mod test {

// Inserting again would be a problem.
prop_assert_eq!(index.idx.len(), 1);
prop_assert_eq!(index.violates_unique_constraint(&cols, &pv), true);
prop_assert_eq!(violates_unique_constraint(&index, &cols, &pv), true);
prop_assert_eq!(
index.get_rows_that_violate_unique_constraint(&value).unwrap().collect::<Vec<_>>(),
[ptr]
Expand Down
6 changes: 1 addition & 5 deletions crates/vm/src/relation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use spacetimedb_table::read_column::ReadColumn;
use spacetimedb_table::table::RowRef;
use std::borrow::Cow;
use std::hash::{Hash, Hasher};
use std::mem;
use std::sync::Arc;

/// RelValue represents either a reference to a row in a table,
Expand Down Expand Up @@ -97,10 +96,7 @@ impl<'a> RelValue<'a> {
fn read_or_take_column(&mut self, col: usize) -> Option<AlgebraicValue> {
match self {
Self::Row(row_ref) => AlgebraicValue::read_column(*row_ref, col).ok(),
Self::Projection(pv) => {
let elem = pv.elements.get_mut(col)?;
Some(mem::replace(elem, AlgebraicValue::U8(0)))
}
Self::Projection(pv) => pv.elements.get_mut(col).map(AlgebraicValue::take),
}
}

Expand Down

1 comment on commit b6c0e1c

@github-actions
Copy link

@github-actions github-actions bot commented on b6c0e1c Mar 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Criterion benchmark results

Criterion benchmark report

YOU SHOULD PROBABLY IGNORE THESE RESULTS.

Criterion is a wall time based benchmarking system that is extremely noisy when run on CI. We collect these results for longitudinal analysis, but they are not reliable for comparing individual PRs.

Go look at the callgrind report instead.

empty

db on disk new latency old latency new throughput old throughput
sqlite 💿 429.8±1.92ns 432.8±1.87ns - -
sqlite 🧠 425.7±3.24ns 422.8±3.15ns - -
stdb_raw 💿 704.9±1.15ns 706.0±1.36ns - -
stdb_raw 🧠 683.0±1.07ns 685.4±0.83ns - -

insert_1

db on disk schema indices preload new latency old latency new throughput old throughput

insert_bulk

db on disk schema indices preload count new latency old latency new throughput old throughput
sqlite 💿 u32_u64_str btree_each_column 2048 256 520.3±1.06µs 515.0±0.49µs 1922 tx/sec 1941 tx/sec
sqlite 💿 u32_u64_str unique_0 2048 256 141.3±0.34µs 136.2±0.44µs 6.9 Ktx/sec 7.2 Ktx/sec
sqlite 💿 u32_u64_u64 btree_each_column 2048 256 426.3±1.39µs 421.8±0.84µs 2.3 Ktx/sec 2.3 Ktx/sec
sqlite 💿 u32_u64_u64 unique_0 2048 256 130.5±0.57µs 127.1±0.51µs 7.5 Ktx/sec 7.7 Ktx/sec
sqlite 🧠 u32_u64_str btree_each_column 2048 256 450.7±1.04µs 447.5±0.56µs 2.2 Ktx/sec 2.2 Ktx/sec
sqlite 🧠 u32_u64_str unique_0 2048 256 126.7±0.84µs 120.1±0.63µs 7.7 Ktx/sec 8.1 Ktx/sec
sqlite 🧠 u32_u64_u64 btree_each_column 2048 256 373.9±0.55µs 370.0±0.26µs 2.6 Ktx/sec 2.6 Ktx/sec
sqlite 🧠 u32_u64_u64 unique_0 2048 256 113.4±0.83µs 109.3±1.04µs 8.6 Ktx/sec 8.9 Ktx/sec
stdb_raw 💿 u32_u64_str btree_each_column 2048 256 724.5±0.65µs 721.7±0.26µs 1380 tx/sec 1385 tx/sec
stdb_raw 💿 u32_u64_str unique_0 2048 256 625.2±0.76µs 628.0±0.51µs 1599 tx/sec 1592 tx/sec
stdb_raw 💿 u32_u64_u64 btree_each_column 2048 256 413.9±0.31µs 416.9±0.12µs 2.4 Ktx/sec 2.3 Ktx/sec
stdb_raw 💿 u32_u64_u64 unique_0 2048 256 364.3±0.44µs 365.6±0.38µs 2.7 Ktx/sec 2.7 Ktx/sec
stdb_raw 🧠 u32_u64_str btree_each_column 2048 256 498.5±0.45µs 497.3±0.16µs 2005 tx/sec 2011 tx/sec
stdb_raw 🧠 u32_u64_str unique_0 2048 256 407.9±0.62µs 407.7±0.83µs 2.4 Ktx/sec 2.4 Ktx/sec
stdb_raw 🧠 u32_u64_u64 btree_each_column 2048 256 312.5±0.22µs 311.9±0.24µs 3.1 Ktx/sec 3.1 Ktx/sec
stdb_raw 🧠 u32_u64_u64 unique_0 2048 256 266.5±0.34µs 269.0±0.86µs 3.7 Ktx/sec 3.6 Ktx/sec

iterate

db on disk schema indices new latency old latency new throughput old throughput
sqlite 💿 u32_u64_str unique_0 22.5±0.17µs 22.0±0.10µs 43.4 Ktx/sec 44.3 Ktx/sec
sqlite 💿 u32_u64_u64 unique_0 20.5±0.12µs 20.2±0.10µs 47.6 Ktx/sec 48.3 Ktx/sec
sqlite 🧠 u32_u64_str unique_0 20.9±0.12µs 20.7±0.17µs 46.6 Ktx/sec 47.1 Ktx/sec
sqlite 🧠 u32_u64_u64 unique_0 19.4±0.12µs 18.9±0.20µs 50.3 Ktx/sec 51.7 Ktx/sec
stdb_raw 💿 u32_u64_str unique_0 18.7±0.00µs 18.7±0.00µs 52.3 Ktx/sec 52.3 Ktx/sec
stdb_raw 💿 u32_u64_u64 unique_0 15.8±0.00µs 15.8±0.00µs 61.7 Ktx/sec 61.7 Ktx/sec
stdb_raw 🧠 u32_u64_str unique_0 18.6±0.00µs 18.6±0.00µs 52.4 Ktx/sec 52.4 Ktx/sec
stdb_raw 🧠 u32_u64_u64 unique_0 15.8±0.00µs 15.8±0.00µs 61.8 Ktx/sec 61.8 Ktx/sec

find_unique

db on disk key type preload new latency old latency new throughput old throughput

filter

db on disk key type index strategy load count new latency old latency new throughput old throughput
sqlite 💿 string index 2048 256 74.0±0.19µs 67.7±0.15µs 13.2 Ktx/sec 14.4 Ktx/sec
sqlite 💿 u64 index 2048 256 69.9±0.21µs 63.3±0.32µs 14.0 Ktx/sec 15.4 Ktx/sec
sqlite 🧠 string index 2048 256 72.6±0.18µs 65.6±0.24µs 13.5 Ktx/sec 14.9 Ktx/sec
sqlite 🧠 u64 index 2048 256 66.1±0.30µs 58.9±0.40µs 14.8 Ktx/sec 16.6 Ktx/sec
stdb_raw 💿 string index 2048 256 5.6±0.00µs 5.6±0.00µs 175.4 Ktx/sec 173.5 Ktx/sec
stdb_raw 💿 u64 index 2048 256 5.5±0.00µs 5.5±0.00µs 176.0 Ktx/sec 178.1 Ktx/sec
stdb_raw 🧠 string index 2048 256 5.5±0.00µs 5.6±0.00µs 176.5 Ktx/sec 174.4 Ktx/sec
stdb_raw 🧠 u64 index 2048 256 5.5±0.00µs 5.4±0.00µs 177.1 Ktx/sec 179.6 Ktx/sec

serialize

schema format count new latency old latency new throughput old throughput
u32_u64_str bflatn_to_bsatn_fast_path 100 4.0±0.00µs 4.0±0.01µs 24.1 Mtx/sec 24.1 Mtx/sec
u32_u64_str bflatn_to_bsatn_slow_path 100 3.7±0.01µs 3.7±0.01µs 25.8 Mtx/sec 26.0 Mtx/sec
u32_u64_str bsatn 100 2.4±0.03µs 2.4±0.01µs 39.5 Mtx/sec 40.4 Mtx/sec
u32_u64_str json 100 5.4±0.02µs 5.4±0.03µs 17.7 Mtx/sec 17.6 Mtx/sec
u32_u64_str product_value 100 644.5±0.39ns 646.8±8.28ns 148.0 Mtx/sec 147.5 Mtx/sec
u32_u64_u64 bflatn_to_bsatn_fast_path 100 1313.5±4.39ns 1388.3±1.72ns 72.6 Mtx/sec 68.7 Mtx/sec
u32_u64_u64 bflatn_to_bsatn_slow_path 100 2.9±0.01µs 2.9±0.01µs 32.9 Mtx/sec 32.9 Mtx/sec
u32_u64_u64 bsatn 100 1669.7±41.50ns 1630.7±67.15ns 57.1 Mtx/sec 58.5 Mtx/sec
u32_u64_u64 json 100 3.0±0.02µs 3.2±0.03µs 31.4 Mtx/sec 30.0 Mtx/sec
u32_u64_u64 product_value 100 559.7±0.49ns 560.1±0.61ns 170.4 Mtx/sec 170.3 Mtx/sec
u64_u64_u32 bflatn_to_bsatn_fast_path 100 1083.9±2.94ns 1083.1±3.11ns 88.0 Mtx/sec 88.0 Mtx/sec
u64_u64_u32 bflatn_to_bsatn_slow_path 100 2.9±0.01µs 2.9±0.01µs 32.6 Mtx/sec 32.7 Mtx/sec
u64_u64_u32 bsatn 100 1695.6±27.30ns 1712.5±3.10ns 56.2 Mtx/sec 55.7 Mtx/sec
u64_u64_u32 json 100 3.5±0.04µs 3.4±0.03µs 27.0 Mtx/sec 27.8 Mtx/sec
u64_u64_u32 product_value 100 598.6±2.16ns 598.6±0.47ns 159.3 Mtx/sec 159.3 Mtx/sec

stdb_module_large_arguments

arg size new latency old latency new throughput old throughput
64KiB 88.6±6.26µs 91.2±10.26µs - -

stdb_module_print_bulk

line count new latency old latency new throughput old throughput
1 46.6±3.96µs 41.3±6.16µs - -
100 351.4±10.11µs 339.7±11.17µs - -
1000 3.0±0.02ms 2.8±0.20ms - -

remaining

name new latency old latency new throughput old throughput
sqlite/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 50.2±0.11µs 50.1±0.16µs 19.5 Ktx/sec 19.5 Ktx/sec
sqlite/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 43.4±0.27µs 43.3±0.55µs 22.5 Ktx/sec 22.5 Ktx/sec
sqlite/🧠/update_bulk/u32_u64_str/unique_0/load=2048/count=256 42.4±0.39µs 43.0±0.23µs 23.0 Ktx/sec 22.7 Ktx/sec
sqlite/🧠/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 37.2±0.13µs 35.8±0.21µs 26.2 Ktx/sec 27.3 Ktx/sec
stdb_module/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 2.9±0.03ms 2.8±0.01ms 339 tx/sec 352 tx/sec
stdb_module/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 1844.5±6.98µs 1834.4±3.82µs 542 tx/sec 545 tx/sec
stdb_raw/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 1141.4±63.35µs 1117.9±1.45µs 876 tx/sec 894 tx/sec
stdb_raw/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 730.6±0.55µs 729.1±0.40µs 1368 tx/sec 1371 tx/sec
stdb_raw/🧠/update_bulk/u32_u64_str/unique_0/load=2048/count=256 787.3±0.77µs 790.6±0.50µs 1270 tx/sec 1264 tx/sec
stdb_raw/🧠/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 536.7±0.79µs 534.4±0.30µs 1863 tx/sec 1871 tx/sec

Please sign in to comment.