diff --git a/betree/pmem-hashmap/src/allocator.rs b/betree/pmem-hashmap/src/allocator.rs index 6c50977f..f53e0556 100644 --- a/betree/pmem-hashmap/src/allocator.rs +++ b/betree/pmem-hashmap/src/allocator.rs @@ -3,13 +3,15 @@ use errno::errno; use std::alloc::{AllocError, Allocator}; use std::fmt::Debug; use std::marker::PhantomData; -use std::ops::Deref; +use std::ops::{Deref, DerefMut}; +use std::sync::atomic::AtomicU64; use std::{ffi::c_void, ptr::NonNull, sync::Arc}; use thiserror::Error; // A friendly persistent memory allocator. #[derive(Clone, Debug)] pub struct Pal { + pub allocations: Arc, pool: Arc>, } @@ -118,6 +120,31 @@ impl PartialEq for PMEMoid { impl Eq for PMEMoid {} +pub struct Fuck<'a, T> { + oid: &'a mut PalPtr, + val: &'a mut T, +} + +impl<'a, T> Deref for Fuck<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.val + } +} + +impl<'a, T> DerefMut for Fuck<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.val + } +} + +impl<'a, T> Drop for Fuck<'a, T> { + fn drop(&mut self) { + self.oid.persist() + } +} + impl PalPtr { /// Translate this persistent ptr to a volatile one. pub fn load(&self) -> &T { @@ -128,6 +155,13 @@ impl PalPtr { unsafe { (haura_direct(self.inner) as *mut T).as_mut().unwrap() } } + pub fn load_mut_safe(&mut self) -> Fuck { + Fuck { + val: unsafe { (haura_direct(self.inner) as *mut T).as_mut().unwrap() }, + oid: self, + } + } + pub fn init(&mut self, src: *const T, count: usize) { unsafe { (haura_direct(self.inner) as *mut T).copy_from(src, count) } } @@ -166,6 +200,17 @@ impl PalPtr { pub fn free(&mut self) { unsafe { pmemobj_free(&mut self.inner) } } + + pub fn persist(&self) { + println!("Persisting {:?}", self.inner); + unsafe { + pmemobj_persist( + pmemobj_pool_by_oid(self.inner), + haura_direct(self.inner), + self.size, + ) + }; + } } // TODO: Impl Deref with typization? @@ -198,6 +243,7 @@ impl Pal { fn new(pool: *mut pmemobjpool) -> Result { NonNull::new(pool) .map(|valid| Pal { + allocations: Arc::new(AtomicU64::new(0)), pool: Arc::new(valid), }) .ok_or_else(|| { @@ -219,7 +265,6 @@ impl Pal { pub fn allocate_variable(&self, v: T) -> Result, PalError> { let mut ptr = self.allocate(std::mem::size_of_val(&v))?; - assert!(ptr.size < 8192); ptr.init(&v, std::mem::size_of_val(&v)); Ok(ptr) } @@ -227,7 +272,7 @@ impl Pal { /// Allocate an area of size in the persistent memory. Allocations are /// always guaranteed to be cache line aligned for Optane PMem (64 bytes). pub fn allocate(&self, size: usize) -> Result, PalError> { - assert!(size < 8192); + dbg!(self.allocations.load(std::sync::atomic::Ordering::Relaxed)); let mut oid = std::mem::MaybeUninit::::uninit(); if unsafe { haura_alloc( @@ -249,6 +294,8 @@ impl Pal { if unsafe { oid_is_null(oid.assume_init_read()) } { return Err(PalError::NullEncountered); } + self.allocations + .fetch_add(size as u64, std::sync::atomic::Ordering::Relaxed); Ok(PalPtr { inner: unsafe { oid.assume_init() }, size, diff --git a/betree/src/replication/tree.rs b/betree/src/replication/tree.rs index 2051667a..ca41ff0b 100644 --- a/betree/src/replication/tree.rs +++ b/betree/src/replication/tree.rs @@ -33,7 +33,6 @@ impl std::fmt::Debug for N } } -#[derive(Debug)] pub enum Link { Entry(V), Child(PalPtr>), @@ -63,124 +62,128 @@ impl PBTree { pub fn get(&self, key: &K) -> Option<&V> { let mut node = &self.root; loop { - dbg!(node); + // dbg!(node); + if node.load().children.size() > 100 { + println!("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ LINK IS BROKEN $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"); + dbg!(node); + println!("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"); + } match node.load().walk(key) { NodeWalk::Miss => return None, NodeWalk::Found(idx) => return node.load().get(idx), - NodeWalk::Child(idx) => { - match node.load().children.get(idx).unwrap() { - Link::Entry(_) => unreachable!(), - Link::Child(ref n) => node = n, - // Child::Node(ref n) => node = n, - // Child::Leaf => unreachable!(), - } - } - } - } - } - - pub fn remove(&mut self, key: &K) { - let mut node = &mut self.root; - let mut path = vec![]; - loop { - path.push(node.clone()); - match node.load().walk(&key) { - NodeWalk::Miss => break, - NodeWalk::Found(_) => { - // Found leaf containing node, escalate removal upwards until no more changes required - // - // Each deletion can have multiple cases: - // - // - Leafs are fine (OK) - // - Leafs are underfilled: - // - Move elements from neighboring leafs (left or right) and change pivot elements accordingly - // - All other leafs are of size MIN, merge children. - // - Parents contain key as index: Delete and replace with highest element from left child - - if node.load_mut().remove(key) { - // Treat small leaf - // 1. Check if left or right child has enough elements - if path.is_empty() { - // emptied root node - return; - } - let mut parent = path.last_mut().unwrap().load_mut(); - let idx = match parent.walk(key) { - NodeWalk::Child(idx) => idx, - _ => unreachable!(), - }; - - if idx > 0 - && parent - .children - .get_mut(idx - 1) - .unwrap() - .assert_child() - .load() - .size() - > MIN - { - // Pick from left child - let left = parent - .children - .get_mut(idx - 1) - .unwrap() - .assert_child() - .load_mut(); - - let new_child = left.children.pop_back().unwrap(); - let new_pivot = left.pivots.pop_back().unwrap(); - node.load_mut().children.push_front(new_child); - node.load_mut().pivots.push_front(new_pivot); - *parent.pivots.get_mut(idx).unwrap() = left.pivot_high(); - } - - if idx + 1 < B - && parent - .children - .get_mut(idx + 1) - .unwrap() - .assert_child() - .load() - .size() - > MIN - { - // Pick from right child - let right = parent - .children - .get_mut(idx + 1) - .unwrap() - .assert_child() - .load_mut(); - - let new_child = right.children.pop_front().unwrap(); - let new_pivot = right.pivots.pop_front().unwrap(); - node.load_mut().children.push_back(new_child); - node.load_mut().pivots.push_back(new_pivot); - *parent.pivots.get_mut(idx).unwrap() = node.load().pivot_high(); - } - - todo!("Merge children") - } else { - // Remove from parents if they contain the key - for mut n in path.into_iter() { - assert!(!n.load_mut().remove(key)) - } - } - break; - } - NodeWalk::Child(idx) => match node.load_mut().children.get_mut(idx).unwrap() { + NodeWalk::Child(idx) => match node.load().children.get(idx).unwrap() { Link::Entry(_) => unreachable!(), - Link::Child(ref mut n) => node = n, + Link::Child(ref n) => node = n, }, } } } + // pub fn remove(&mut self, key: &K) { + // let mut node = &mut self.root; + // let mut path = vec![]; + // loop { + // path.push(node.clone()); + // match node.load().walk(&key) { + // NodeWalk::Miss => break, + // NodeWalk::Found(_) => { + // // Found leaf containing node, escalate removal upwards until no more changes required + // // + // // Each deletion can have multiple cases: + // // + // // - Leafs are fine (OK) + // // - Leafs are underfilled: + // // - Move elements from neighboring leafs (left or right) and change pivot elements accordingly + // // - All other leafs are of size MIN, merge children. + // // - Parents contain key as index: Delete and replace with highest element from left child + + // if node.load_mut_safe().remove(key) { + // // Treat small leaf + // // 1. Check if left or right child has enough elements + // if path.is_empty() { + // // emptied root node + // return; + // } + // let mut parent = path.last_mut().unwrap().load_mut_safe(); + // let idx = match parent.walk(key) { + // NodeWalk::Child(idx) => idx, + // _ => unreachable!(), + // }; + + // if idx > 0 + // && parent + // .children + // .get_mut(idx - 1) + // .unwrap() + // .assert_child() + // .load() + // .size() + // > MIN + // { + // // Pick from left child + // let left = parent + // .children + // .get_mut(idx - 1) + // .unwrap() + // .assert_child() + // .load_mut(); + + // let new_child = left.children.pop_back().unwrap(); + // let new_pivot = left.pivots.pop_back().unwrap(); + // node.load_mut().children.push_front(new_child); + // node.load_mut().pivots.push_front(new_pivot); + // *parent.pivots.get_mut(idx).unwrap() = left.pivot_high(); + // } + + // if idx + 1 < B + // && parent + // .children + // .get_mut(idx + 1) + // .unwrap() + // .assert_child() + // .load() + // .size() + // > MIN + // { + // // Pick from right child + // let right = parent + // .children + // .get_mut(idx + 1) + // .unwrap() + // .assert_child() + // .load_mut(); + + // let new_child = right.children.pop_front().unwrap(); + // let new_pivot = right.pivots.pop_front().unwrap(); + // node.load_mut().children.push_back(new_child); + // node.load_mut().pivots.push_back(new_pivot); + // *parent.pivots.get_mut(idx).unwrap() = node.load().pivot_high(); + // } + + // todo!("Merge children") + // } else { + // // Remove from parents if they contain the key + // for mut n in path.into_iter() { + // assert!(!n.load_mut_safe().remove(key)) + // } + // } + // break; + // } + // NodeWalk::Child(idx) => { + // match node.clone().load_mut_safe().children.get_mut(idx).unwrap() { + // Link::Entry(_) => unreachable!(), + // Link::Child(ref mut n) => node = n, + // } + // } + // } + // } + // } + pub fn insert(&mut self, key: K, val: V, pal: &Pal) { - if let Some((k, v, n)) = self.insert_from(key, val, pal, self.root.clone()) { - assert!(self.insert_from(k, v, pal, n).is_none()); + if let Some((k, v)) = self.insert_from(key, val, pal, self.root.clone()) { + assert!(self.insert_from(k, v, pal, self.root).is_none()); } + println!("inserted"); } fn insert_from( @@ -189,15 +192,16 @@ impl PBTree { val: V, pal: &Pal, mut from: PalPtr>, - ) -> Option<(K, V, PalPtr>)> { - let mut node = &mut from; + ) -> Option<(K, V)> { + println!("insert from"); + let mut node = from; let mut path = vec![]; loop { path.push(node.clone()); match node.load().walk(&key) { NodeWalk::Miss => { return if let Some((median, new_node, value)) = - node.load_mut().insert(key.clone(), val) + node.load_mut_safe().insert(key.clone(), val) { // Insert facilitated a split, insert new node into parent let mut pair = Some((median, new_node)).map(|(key, new_node)| { @@ -205,14 +209,17 @@ impl PBTree { (key, pal.allocate_variable(new_node).unwrap()) }); for mut cur_node in path.iter_mut().rev().skip(1) { + dbg!(&cur_node); if let Some((key, new_node)) = pair { - pair = cur_node.load_mut().escalate(key, new_node).map( - |(key, new_node)| { - // Allocate the new node - (key, pal.allocate_variable(new_node).unwrap()) - }, - ); - node = cur_node; + dbg!(cur_node.load().children.size()); + // let foo = pal.allocate::(64); + // dbg!(cur_node.load().children.size()); + let mut foo = cur_node.load_mut_safe(); + pair = foo.escalate(key, new_node).map(|(key, new_node)| { + // Allocate the new node + (key, pal.allocate_variable(new_node).unwrap()) + }); + dbg!(foo.children.size()); } else { break; } @@ -224,18 +231,19 @@ impl PBTree { let mut new_root = Node::new(); new_root.pivots.push_front(key); // new_root.pivots.push_back(new_node.load().pivot_high()); + println!("Old root: {:?}", self.root); new_root.children.push_front(Link::Child(self.root)); new_root.children.push_back(Link::Child(new_node)); self.root = pal.allocate_variable(new_root).unwrap(); - node = &mut self.root; + dbg!(self.root); } - Some((key, value, node.clone())) + Some((key, value)) } else { None }; } NodeWalk::Found(idx) => { - node.load_mut() + node.load_mut_safe() .children .get_mut(idx) .map(|entry| match entry { @@ -244,10 +252,12 @@ impl PBTree { }); return None; } - NodeWalk::Child(idx) => match node.load_mut().children.get_mut(idx).unwrap() { - Link::Entry(_) => unreachable!(), - Link::Child(ref mut n) => node = n, - }, + NodeWalk::Child(idx) => { + match node.clone().load_mut_safe().children.get_mut(idx).unwrap() { + Link::Entry(_) => unreachable!(), + Link::Child(ref mut n) => node = n.clone(), + } + } } } } @@ -313,10 +323,15 @@ impl Node { pub fn split(&mut self) -> (K, Node) { assert!(self.pivots.size() == NUM_KEYS); assert!(self.children.size() >= NUM_KEYS); - const idx: usize = NUM_KEYS / 2 + NUM_KEYS % 2; + const idx: usize = NUM_KEYS / 2 + NUM_KEYS % 2 - 1; + dbg!(idx); let right_pivots = self.pivots.split_after(idx); let right_children = self.children.split_after(idx); + dbg!(self.pivots.size()); + dbg!(self.children.size()); + dbg!(right_pivots.size()); + dbg!(right_children.size()); let right = Self { pivots: right_pivots, @@ -328,8 +343,6 @@ impl Node { } pub fn escalate(&mut self, key: K, right: PalPtr>) -> Option<(K, Node)> { - dbg!(&self.pivots.size()); - dbg!(&self.children.size()); if self.pivots.size() <= NUM_KEYS && self.children.size() < B { println!("can buffer node"); // Shift pivot and child @@ -340,10 +353,13 @@ impl Node { // Children space is available, shift self.pivots.insert(idx, key); self.children.insert(idx + 1, Link::Child(right)); + dbg!(self.children.size()); None } else { let (upper, mut new_right) = self.split(); + dbg!(self.children.size()); assert!(new_right.escalate(key, right).is_none()); + dbg!(self.children.size()); Some((upper, new_right)) } } @@ -481,7 +497,6 @@ mod tests { println!("{id}"); tree.insert(id, id, &pal); for n in 0..=id { - println!("id: {n}"); assert_eq!(tree.get(&n), Some(&n)); } }