Skip to content

Commit

Permalink
Refactor StorageVal (remove StoragePoint)
Browse files Browse the repository at this point in the history
  • Loading branch information
voltrevo committed Oct 27, 2023
1 parent 15f6b23 commit 884bcad
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 165 deletions.
9 changes: 3 additions & 6 deletions storage/src/storage_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ where
None => return Ok(None),
};

let value = self.read(key)?.map(|entry| entry.to_val());
let value = self.read(key)?.map(|entry| entry.move_to_val());

Ok(value)
}
Expand All @@ -74,10 +74,7 @@ where
fn store_with_replacements(&mut self, value: &StorageVal) -> Result<StorageEntryPtr, E> {
let mut cache = HashMap::<RcKey, StorageEntryPtr>::new();

if let Some(key) = value
.point
.maybe_replace_store(self, &value.refs, &mut cache)?
{
if let Some(key) = value.maybe_replace_store(self, &mut cache)? {
return Ok(key);
}

Expand All @@ -89,7 +86,7 @@ where
self.write(key, Some(&value.to_entry()))?;
self.ref_delta(key, -1)?; // Cancel out the assumed single reference

for subkey in value.refs.iter() {
for subkey in value.refs_iter() {
self.ref_delta(*subkey, 1)?;
}

Expand Down
243 changes: 143 additions & 100 deletions storage/src/storage_val.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,51 +11,74 @@ use crate::storage_ptr::StorageEntryPtr;
#[cfg(test)]
use crate::{Storage, StorageBackend};

#[derive(Serialize, Deserialize, Debug)]
pub struct StorageVal {
pub point: StoragePoint,
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
pub enum StorageVal {
#[default]
Void,
Number(u64),
Ptr(StorageEntryPtr),
Ref(u64),
Compound(
#[serde(serialize_with = "serialize_rc", deserialize_with = "deserialize_rc")]
Rc<StorageCompoundVal>,
),
}

#[serde(serialize_with = "serialize_rc", deserialize_with = "deserialize_rc")]
pub refs: Rc<Vec<StorageEntryPtr>>,
#[derive(Debug, Serialize, Deserialize)]
pub enum StorageCompoundVal {
Array(StorageArray),
}

#[derive(Debug, Serialize, Deserialize)]
pub struct StorageArray {
pub items: Vec<StorageVal>,

// Skipping serialization because they're stored in the entry. When converting from an entry, we
// copy (todo: move?) the refs from there.
#[serde(skip)]
pub refs: Vec<StorageEntryPtr>,
}

impl StorageVal {
pub fn to_entry(&self) -> StorageEntry {
StorageEntry {
ref_count: 1,
refs: self.refs.clone(),
data: bincode::serialize(&self.point).unwrap(),
refs: match self {
StorageVal::Void | StorageVal::Number(_) | StorageVal::Ptr(_) | StorageVal::Ref(_) => {
vec![]
}
StorageVal::Compound(compound) => match &**compound {
StorageCompoundVal::Array(arr) => arr.refs.clone(),
},
},
data: bincode::serialize(self).unwrap(),
}
}

pub fn refs(&self) -> Option<&Vec<StorageEntryPtr>> {
match self {
StorageVal::Void | StorageVal::Number(_) | StorageVal::Ptr(_) | StorageVal::Ref(_) => None,
StorageVal::Compound(compound) => match &**compound {
StorageCompoundVal::Array(arr) => Some(&arr.refs),
},
}
}

pub fn refs_iter(&self) -> impl Iterator<Item = &StorageEntryPtr> {
self.refs().into_iter().flatten()
}

#[cfg(test)]
pub(crate) fn numbers<SB: StorageBackend>(
&self,
storage: &mut Storage<SB>,
) -> Result<Vec<u64>, SB::Error<()>> {
storage
.sb
.transaction(|sb| self.point.numbers(sb, &self.refs))
storage.sb.transaction(|sb| self.numbers_impl(sb))
}
}

#[derive(Default, Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
pub enum StoragePoint {
#[default]
Void,
Number(u64),
Array(
#[serde(serialize_with = "serialize_rc", deserialize_with = "deserialize_rc")]
Rc<Vec<StoragePoint>>,
),
Ref(u64),
}

impl StoragePoint {
pub fn maybe_replace_store<E, SO: StorageOps<E>>(
&self,
tx: &mut SO,
refs: &Rc<Vec<StorageEntryPtr>>,
cache: &mut HashMap<RcKey, StorageEntryPtr>,
) -> Result<Option<StorageEntryPtr>, E> {
if let Some(id) = self.cache_id() {
Expand All @@ -65,114 +88,134 @@ impl StoragePoint {
}

Ok(match &self {
StoragePoint::Void => None,
StoragePoint::Number(_) => None,
StoragePoint::Array(arr) => 'b: {
let mut replacements: Vec<(usize, StorageEntryPtr)> = Vec::new();

for i in 0..arr.len() {
if let Some(key) = arr[i].maybe_replace_store(tx, refs, cache)? {
replacements.push((i, key));
StorageVal::Void | StorageVal::Number(_) | StorageVal::Ptr(_) | StorageVal::Ref(_) => None,
StorageVal::Compound(compound) => match &**compound {
StorageCompoundVal::Array(arr) => 'b: {
let mut replacements: Vec<(usize, StorageEntryPtr)> = Vec::new();

for i in 0..arr.items.len() {
if let Some(key) = arr.items[i].maybe_replace_store(tx, cache)? {
replacements.push((i, key));
}
}
}

if replacements.is_empty() {
break 'b Some(cache_and_store(
tx,
&StorageVal {
point: StoragePoint::Array(arr.clone()),
refs: refs.clone(),
},
cache,
RcKey::from(arr.clone()),
)?);
}
let cache_id = RcKey::from(compound.clone());

let mut new_arr = Vec::<StoragePoint>::new();
let mut new_refs = (**refs).clone();
if replacements.is_empty() {
break 'b Some(cache_and_store(tx, self, cache, cache_id)?);
}

let mut new_arr = Vec::<StorageVal>::new();
let mut new_refs = arr.refs.clone();

let mut replacements_iter = replacements.iter();
let mut next_replacement = replacements_iter.next();
let mut replacements_iter = replacements.iter();
let mut next_replacement = replacements_iter.next();

for (i, point) in arr.iter().enumerate() {
if let Some((j, entry_ptr)) = next_replacement {
if *j == i {
new_arr.push(StoragePoint::Ref(new_refs.len() as u64));
new_refs.push(*entry_ptr);
next_replacement = replacements_iter.next();
continue;
for (i, item) in arr.items.iter().enumerate() {
if let Some((j, entry_ptr)) = next_replacement {
if *j == i {
new_arr.push(StorageVal::Ref(new_refs.len() as u64));
new_refs.push(*entry_ptr);
next_replacement = replacements_iter.next();
continue;
}
}

new_arr.push(item.clone());
}

new_arr.push(point.clone());
Some(cache_and_store(
tx,
&StorageVal::Compound(Rc::new(StorageCompoundVal::Array(StorageArray {
items: new_arr,
refs: new_refs,
}))),
cache,
cache_id,
)?)
}

Some(cache_and_store(
tx,
&StorageVal {
point: StoragePoint::Array(Rc::new(new_arr)),
refs: Rc::new(new_refs),
},
cache,
RcKey::from(arr.clone()),
)?)
}
StoragePoint::Ref(_) => None,
},
})
}

fn cache_id(&self) -> Option<RcKey> {
match &self {
StoragePoint::Void => None,
StoragePoint::Number(_) => None,
StoragePoint::Array(arr) => Some(RcKey::from(arr.clone())),
StoragePoint::Ref(_) => None,
match self {
StorageVal::Void => None,
StorageVal::Number(_) => None,
StorageVal::Ptr(_) => None,
StorageVal::Ref(_) => None,
StorageVal::Compound(compound) => Some(RcKey::from(compound.clone())),
}
}

#[cfg(test)]
fn numbers<E, SO: StorageOps<E>>(
&self,
tx: &mut SO,
refs: &Rc<Vec<StorageEntryPtr>>,
) -> Result<Vec<u64>, E> {
fn numbers_impl<E, SO: StorageOps<E>>(&self, tx: &mut SO) -> Result<Vec<u64>, E> {
match &self {
StoragePoint::Void => Ok(Vec::new()),
StoragePoint::Number(n) => Ok(vec![*n]),
StoragePoint::Array(arr) => {
let mut numbers = Vec::new();
StorageVal::Void => Ok(Vec::new()),
StorageVal::Number(n) => Ok(vec![*n]),
StorageVal::Ptr(ptr) => {
let entry = tx.read(*ptr)?.unwrap();
entry.move_to_val().numbers_impl(tx)
}
// StorageVal::Array(arr) => {
// let mut numbers = Vec::new();

for point in arr.iter() {
numbers.extend(point.numbers(tx, refs)?);
}
// for point in arr.iter() {
// numbers.extend(point.numbers(tx, refs)?);
// }

Ok(numbers)
}
StoragePoint::Ref(i) => {
let key = refs[*i as usize];
let val = tx.read(key)?.unwrap().to_val();
val.point.numbers(tx, &val.refs)
// Ok(numbers)
// }
StorageVal::Ref(_) => {
panic!("Can't lookup ref (shouldn't hit this case)")
}
StorageVal::Compound(compound) => match &**compound {
StorageCompoundVal::Array(arr) => {
let mut numbers = Vec::new();

for item in &arr.items {
if let StorageVal::Ref(i) = item {
let item = &StorageVal::Ptr(arr.refs[*i as usize]);
numbers.extend(item.numbers_impl(tx)?);
} else {
numbers.extend(item.numbers_impl(tx)?);
}
}

Ok(numbers)
}
},
}
}
}

#[derive(Serialize, Deserialize)]
pub struct StorageEntry {
pub(crate) ref_count: u64,

#[serde(serialize_with = "serialize_rc", deserialize_with = "deserialize_rc")]
pub(crate) refs: Rc<Vec<StorageEntryPtr>>,
pub(crate) refs: Vec<StorageEntryPtr>,

data: Vec<u8>,
}

impl StorageEntry {
pub fn to_val(&self) -> StorageVal {
StorageVal {
point: bincode::deserialize(&self.data).unwrap(),
refs: self.refs.clone(),
}
pub fn move_to_val(self) -> StorageVal {
let Self {
ref_count: _,
refs,
data,
} = self;

let mut val = bincode::deserialize::<StorageVal>(&data).unwrap();

if let StorageVal::Compound(compound) = &mut val {
match Rc::get_mut(compound).expect("Should be single ref") {
StorageCompoundVal::Array(arr) => {
arr.refs = refs;
}
}
};

val
}
}

Expand Down
Loading

0 comments on commit 884bcad

Please sign in to comment.