Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ members = ["codegen", "examples", "performance_measurement", "performance_measur

[package]
name = "worktable"
version = "0.7.2"
version = "0.8.0"
edition = "2024"
authors = ["Handy-caT"]
license = "MIT"
Expand All @@ -27,9 +27,9 @@ lockfree = { version = "0.5.1" }
fastrand = "2.3.0"
futures = "0.3.30"
uuid = { version = "1.10.0", features = ["v4", "v7"] }
data_bucket = "0.2.10"
data_bucket = "0.3.0"
# data_bucket = { git = "https://github.com/pathscale/DataBucket", branch = "page_cdc_correction", version = "0.2.7" }
# data_bucket = { path = "../DataBucket", version = "0.2.9" }
# data_bucket = { path = "../DataBucket", version = "0.2.10" }
performance_measurement_codegen = { path = "performance_measurement/codegen", version = "0.1.0", optional = true }
performance_measurement = { path = "performance_measurement", version = "0.1.0", optional = true }
# indexset = { version = "0.12.3", features = ["concurrent", "cdc", "multimap"] }
Expand Down
12 changes: 11 additions & 1 deletion examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,14 @@ name = "wt-examples"
version = "0.1.0"
edition = "2021"

[dependencies]
[dependencies]
worktable = { path = "../", version = "0.8.0" }
tokio = { version = "1.39.2", features = ["full"] }
rkyv = { version = "0.8.9", features = ["uuid-1"] }
eyre = "0.6.12"
serde = { version = "1.0.215", features = ["derive"] }
futures = "0.3.30"
uuid = { version = "1.8.0", features = ["v4", "serde"] }
derive_more = { version = "1.0.0", features = ["full"] }
atomic_float = "1.1.0"
rand = "0.9.1"
106 changes: 0 additions & 106 deletions examples/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,107 +1 @@
// use futures::executor::block_on;
// use worktable::prelude::*;
// use worktable::worktable;
//
// #[tokio::main]
// async fn main() {
// // describe WorkTable
// worktable!(
// name: My,
// persist: true,
// columns: {
// id: u64 primary_key autoincrement,
// val: i64,
// test: i32,
// attr: String,
// attr2: i32,
// attr_float: f64,
// attr_string: String,
//
// },
// indexes: {
// idx1: attr,
// idx2: attr2 unique,
// idx3: attr_string,
// },
// queries: {
// update: {
// ValById(val) by id,
// AllAttrById(attr, attr2) by id,
// UpdateOptionalById(test) by id,
// },
// delete: {
// ByAttr() by attr,
// ById() by id,
// }
// }
// );
//
// // Init Worktable
// let config = PersistenceConfig::new("data", "data");
// let my_table = MyWorkTable::new(config).await.unwrap();
//
// // WT rows (has prefix My because of table name)
// let row = MyRow {
// val: 777,
// attr: "Attribute0".to_string(),
// attr2: 345,
// test: 1,
// id: 0,
// attr_float: 100.0,
// attr_string: "String_attr0".to_string(),
// };
//
// for i in 2..1000000_i64 {
// let row = MyRow {
// val: 777,
// attr: format!("Attribute{}", i),
// attr2: 345 + i as i32,
// test: i as i32,
// id: i as u64,
// attr_float: 100.0 + i as f64,
// attr_string: format!("String_attr{}", i),
// };
//
// my_table.insert(row).unwrap();
// }
//
// // insert
// let pk: MyPrimaryKey = my_table.insert(row).expect("primary key");
//
// // Select ALL records from WT
// let _select_all = my_table.select_all().execute();
// //println!("Select All {:?}", select_all);
//
// // Select All records with attribute TEST
// let _select_all = my_table.select_all().execute();
// //println!("Select All {:?}", select_all);
//
// // Select by Idx
// //let _select_by_attr = my_table
// // .select_by_attr("Attribute1".to_string())
// // .execute()
// //r .unwrap();
//
// //for row in select_by_attr {
// // println!("Select by idx, row {:?}", row);
// //}
//
// // Update Value query
// let update = my_table.update_val_by_id(ValByIdQuery { val: 1337 }, pk.clone());
// let _ = block_on(update);
//
// let _select_all = my_table.select_all().execute();
// //println!("Select after update val {:?}", select_all);
//
// let delete = my_table.delete(pk);
// let _ = block_on(delete);
//
// let _select_all = my_table.select_all().execute();
// //println!("Select after delete {:?}", select_all);
//
// let info = my_table.system_info();
//
// println!("{info}");
// }

fn main() {}
72 changes: 36 additions & 36 deletions src/index/unsized_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ where
{
inner: Vec<T>,
length_capacity: usize,
length_without_deleted: usize,
removed_length: usize,
length: usize,
}

Expand Down Expand Up @@ -45,9 +45,23 @@ where
inner,
length,
length_capacity,
length_without_deleted: length,
removed_length: 0,
}
}

pub fn rebuild(&mut self) {
self.length = self
.inner
.last()
.expect("should not rebuild on empty node")
.aligned_size();
self.length += UNSIZED_HEADER_LENGTH as usize;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Why are two operations instead of a single assignment?

for value in self.inner.iter() {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Why does the size contains the last item twice?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Node's id is stored separately. This unsized node logic is needed to mirror state of UnsizedPage in data bucket. And this page stores node id as one field, utility fields, slots and inner node values.

self.length += value.aligned_size();
self.length += UnsizedIndexPageUtility::<T>::slots_value_size();
}
self.removed_length = 0;
}
}

impl<T> NodeLike<T> for UnsizedNode<T>
Expand All @@ -59,7 +73,7 @@ where
inner: Vec::new(),
length_capacity: capacity,
length: UNSIZED_HEADER_LENGTH as usize,
length_without_deleted: UNSIZED_HEADER_LENGTH as usize,
removed_length: 0,
}
}

Expand All @@ -68,18 +82,20 @@ where
}

fn halve(&mut self) -> Self {
let middle_length = (self.length_without_deleted
let middle_length = (self.length
- self.removed_length
- (self.max().unwrap().aligned_size() + UNSIZED_HEADER_LENGTH as usize))
/ 2;
let current_node_id_size = self.max().unwrap().aligned_size();
let mut middle_variance = f64::INFINITY;
let mut ind = false;
let mut i = 1;
let mut current_length = 0;
let mut middle_idx = 0;
let mut iter = self.inner.iter();
while !ind {
let val = iter.next().expect("we should stop before node's end");
let Some(val) = iter.next() else {
break;
};
current_length += val.aligned_size();
current_length += UnsizedIndexPageUtility::<T>::slots_value_size();
let current_middle_variance =
Expand All @@ -96,19 +112,8 @@ where
}

let new_inner = self.inner.split_off(middle_idx);
let node_id_len = new_inner.last().unwrap().aligned_size();
let split = Self {
inner: new_inner,
length_capacity: self.length_capacity,
length: self.length_without_deleted - (current_node_id_size + current_length)
+ node_id_len,
length_without_deleted: self.length_without_deleted
- (current_node_id_size + current_length)
+ node_id_len,
};
self.length =
current_length + self.max().unwrap().aligned_size() + UNSIZED_HEADER_LENGTH as usize;
self.length_without_deleted = self.length;
let split = Self::from_inner(new_inner, self.length_capacity);
self.rebuild();

split
}
Expand All @@ -134,13 +139,10 @@ where
// Node id is stored separately too, so we need to count node_id twice
self.length -= node_id_len;
self.length += value_size;
self.length_without_deleted -= node_id_len;
self.length_without_deleted += value_size;
}
self.length += value_size;
self.length += UnsizedIndexPageUtility::<T>::slots_value_size();
self.length_without_deleted += value_size;
self.length_without_deleted += UnsizedIndexPageUtility::<T>::slots_value_size();

(true, idx)
}
(false, idx) => (false, idx),
Expand Down Expand Up @@ -172,16 +174,14 @@ where
where
T: Borrow<Q>,
{
let node_id_len = self.max().map(|v| v.aligned_size()).unwrap_or(0);
// TODO: Refactor this when empty links logic will be added to the page
if let Some((val, i)) = NodeLike::delete(&mut self.inner, value) {
let new_node_id_len = self.max().map(|v| v.aligned_size()).unwrap_or(0);
if new_node_id_len != node_id_len {
self.length_without_deleted -= node_id_len;
self.length_without_deleted += new_node_id_len;
self.removed_length +=
val.aligned_size() + UnsizedIndexPageUtility::<T>::slots_value_size();

if self.removed_length > self.length_capacity / 2 {
self.rebuild()
}
self.length_without_deleted -= val.aligned_size();
self.length_without_deleted -= UnsizedIndexPageUtility::<T>::slots_value_size();
Some((val, i))
} else {
None
Expand Down Expand Up @@ -246,10 +246,10 @@ mod test {
assert_eq!(node.length, node.length_capacity);
let split = node.halve();
assert_eq!(node.length, 152);
assert_eq!(node.length_without_deleted, 152);
assert_eq!(node.removed_length, 0);
assert_eq!(node.inner.len(), 2);
assert_eq!(split.length, 136);
assert_eq!(split.length_without_deleted, 136);
assert_eq!(split.removed_length, 0);
assert_eq!(split.inner.len(), 1);
}

Expand All @@ -258,10 +258,10 @@ mod test {
let mut node = UnsizedNode::<String>::with_capacity(200);
node.insert(String::from_utf8(vec![b'1'; 16]).unwrap());
assert_eq!(node.length, 120);
assert_eq!(node.length_without_deleted, 120);
assert_eq!(node.removed_length, 0);
node.delete(&String::from_utf8(vec![b'1'; 16]).unwrap());
assert_eq!(node.length, 120);
assert_eq!(node.length_without_deleted, 64);
assert_eq!(node.removed_length, 32);
}

#[test]
Expand All @@ -270,10 +270,10 @@ mod test {
node.insert(String::from_utf8(vec![b'1'; 16]).unwrap());
node.insert(String::from_utf8(vec![b'2'; 24]).unwrap());
assert_eq!(node.length, 168);
assert_eq!(node.length_without_deleted, 168);
assert_eq!(node.removed_length, 0);
node.delete(&String::from_utf8(vec![b'2'; 24]).unwrap());
assert_eq!(node.length, 168);
assert_eq!(node.length_without_deleted, 120);
assert_eq!(node.removed_length, 40);
}

#[test]
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified tests/data/expected/space_index_unsized/process_insert_at.wt.idx
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified tests/data/expected/space_index_unsized/process_remove_at.wt.idx
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified tests/data/space_index_unsized/indexset/process_insert_at.wt.idx
Binary file not shown.
Binary file not shown.
Binary file modified tests/data/space_index_unsized/process_create_node.wt.idx
Binary file not shown.
Binary file not shown.
Binary file modified tests/data/space_index_unsized/process_create_second_node.wt.idx
Binary file not shown.
Binary file modified tests/data/space_index_unsized/process_insert_at.wt.idx
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified tests/data/space_index_unsized/process_remove_at.wt.idx
Binary file not shown.
Binary file modified tests/data/space_index_unsized/process_remove_at_node_id.wt.idx
Binary file not shown.
Binary file modified tests/data/space_index_unsized/process_remove_node.wt.idx
Binary file not shown.
Binary file modified tests/data/space_index_unsized/process_split_node.wt.idx
Binary file not shown.
Loading
Loading