use super::{
BTreeSet, Branch, BucketName, Db, Error, HashMap, ReadVersion, RegistryEntry, Result, Snapshot,
Value,
};
pub(super) const TAG_PRESENT: u8 = 0;
pub(super) const TAG_TOMBSTONE: u8 = 1;
pub(super) fn encode_present(value: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(value.len() + 1);
out.push(TAG_PRESENT);
out.extend_from_slice(value);
out
}
pub(super) enum OverlayWrite {
Put(Value),
Delete,
}
pub(super) struct DurableLayer {
pub(super) name: String,
pub(super) written: BTreeSet<String>,
pub(super) at: Option<Snapshot>,
}
pub(super) struct DurableState {
pub(super) chain: Vec<DurableLayer>,
pub(super) leaf_fork: ReadVersion,
pub(super) leaf_parent: Option<String>,
pub(super) leaf_generation: [u8; 16],
}
pub(super) struct BranchLineageBuilder {
leaf_fork: ReadVersion,
leaf_parent: Option<String>,
leaf_generation: [u8; 16],
chain: Vec<DurableLayer>,
child_fork: ReadVersion,
parent: Option<String>,
visited: BTreeSet<String>,
}
impl BranchLineageBuilder {
pub(super) fn new(name: &str, leaf: RegistryEntry) -> Result<Self> {
leaf.lifecycle.require_active()?;
Ok(Self {
leaf_fork: leaf.fork,
leaf_parent: leaf.parent.clone(),
leaf_generation: leaf.generation,
chain: vec![DurableLayer {
name: name.to_owned(),
written: leaf.written_buckets,
at: None,
}],
child_fork: leaf.fork,
parent: leaf.parent,
visited: BTreeSet::from([name.to_owned()]),
})
}
pub(super) fn next_parent(&self) -> Option<String> {
self.parent.clone()
}
pub(super) fn push_parent(
&mut self,
db: &Db,
name: String,
entry: RegistryEntry,
) -> Result<()> {
if !self.visited.insert(name.clone()) {
return Err(Error::Corruption {
message: format!("branch lineage contains a cycle at {name}"),
});
}
entry.lifecycle.require_active()?;
self.chain.push(DurableLayer {
name,
written: entry.written_buckets,
at: Some(db.snapshot_at(self.child_fork)?),
});
self.child_fork = entry.fork;
self.parent = entry.parent;
Ok(())
}
pub(super) fn finish(self, db: &Db) -> Result<Branch<'_>> {
let root_fork = db.snapshot_at(self.child_fork)?;
Ok(Branch::durable(
db,
root_fork,
DurableState {
chain: self.chain,
leaf_fork: self.leaf_fork,
leaf_parent: self.leaf_parent,
leaf_generation: self.leaf_generation,
},
))
}
}
pub(super) enum Backing {
Ephemeral(HashMap<(BucketName, Vec<u8>), OverlayWrite>),
Durable(DurableState),
}