#[cfg(test)]
mod test;
use crate::{
DagMapId, MapxOrdRawKey, Orphan,
common::{
InstanceId,
error::{Result, VsdbError},
},
};
use serde::{Deserialize, Serialize, de};
use std::{
collections::HashSet,
fmt,
ops::{Deref, DerefMut},
result::Result as StdResult,
};
use vsdb_core::{
basic::mapx_raw::{self, MapxRaw},
common::{RawBytes, vsdb_flush},
};
type DagHead = DagMapRaw;
#[derive(Clone, Debug)]
pub struct DagMapRaw {
data: MapxRaw,
parent: Orphan<Option<DagMapRaw>>,
children: MapxOrdRawKey<DagMapRaw>,
}
impl Serialize for DagMapRaw {
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeTuple;
let mut t = serializer.serialize_tuple(3)?;
t.serialize_element(&self.data)?;
t.serialize_element(&self.parent)?;
t.serialize_element(&self.children)?;
t.end()
}
}
impl<'de> Deserialize<'de> for DagMapRaw {
fn deserialize<D>(deserializer: D) -> StdResult<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct Vis;
impl<'de> de::Visitor<'de> for Vis {
type Value = DagMapRaw;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("DagMapRaw")
}
fn visit_seq<A: de::SeqAccess<'de>>(
self,
mut seq: A,
) -> StdResult<DagMapRaw, A::Error> {
let data = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let parent = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
let children = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(2, &self))?;
Ok(DagMapRaw {
data,
parent,
children,
})
}
}
deserializer.deserialize_tuple(3, Vis)
}
}
impl DagMapRaw {
pub fn new_in(ns: &crate::common::Namespace, parent: Option<&mut Self>) -> Self {
ns.scope(|| Self::new(parent))
}
pub fn namespace(&self) -> crate::common::Namespace {
self.data.namespace()
}
pub fn new(parent: Option<&mut Self>) -> Self {
let r = Self {
parent: Orphan::new(parent.as_deref().map(|p| unsafe { p.shadow() })),
data: MapxRaw::new(),
children: MapxOrdRawKey::new(),
};
if let Some(p) = parent {
let child_id = super::gen_dag_map_id_num().to_le_bytes();
debug_assert!(
p.children.get(child_id).is_none(),
"Child ID already exists — possible ID counter rollback"
);
p.children.insert(child_id, &r);
}
r
}
#[inline(always)]
pub unsafe fn shadow(&self) -> Self {
unsafe {
Self {
data: self.data.shadow(),
parent: self.parent.shadow(),
children: self.children.shadow(),
}
}
}
#[inline(always)]
pub fn instance_id(&self) -> InstanceId {
self.data.instance_id()
}
pub fn save_meta(&self) -> Result<InstanceId> {
let id = self.instance_id();
crate::common::save_instance_meta(id, self)?;
Ok(id)
}
pub fn from_meta(instance_id: impl Into<InstanceId>) -> Result<Self> {
crate::common::load_instance_meta(instance_id.into())
}
#[inline(always)]
pub fn is_dead(&self) -> bool {
self.data.iter().all(|(_, v)| v.is_empty())
&& self.parent.get_value().is_none()
&& self.no_children()
}
#[inline(always)]
pub fn no_children(&self) -> bool {
self.children.inner.iter().next().is_none()
}
pub fn get(&self, key: impl AsRef<[u8]>) -> Option<RawBytes> {
let key = key.as_ref();
let mut hdr = self;
let mut hdr_owned;
let mut seen = HashSet::new();
loop {
if !seen.insert(hdr.instance_id()) {
return None;
}
if let Some(v) = hdr.data.get(key) {
return if v.is_empty() { None } else { Some(v) };
}
match hdr.parent.get_value() {
Some(p) => {
hdr_owned = p;
hdr = &hdr_owned;
}
_ => {
return None;
}
}
}
}
#[inline(always)]
pub fn get_mut(&mut self, key: impl AsRef<[u8]>) -> Option<ValueMut<'_>> {
self.data.get_mut(key.as_ref()).and_then(|inner| {
if inner.is_empty() {
return None;
}
Some(ValueMut {
value: inner.clone(),
inner,
dirty: false,
})
})
}
#[inline(always)]
pub fn insert(&mut self, key: impl AsRef<[u8]>, value: impl AsRef<[u8]>) {
assert!(
!value.as_ref().is_empty(),
"empty value is a tombstone; call remove() instead"
);
self.data.insert(key.as_ref(), value)
}
#[inline(always)]
pub fn remove(&mut self, key: impl AsRef<[u8]>) {
self.data.insert(key.as_ref(), [])
}
#[inline(always)]
pub fn prune(self) -> Result<DagHead> {
self.prune_mainline()
}
fn prune_mainline(mut self) -> Result<DagHead> {
let mut linebuf = self.prune_collect_mainline()?;
if linebuf.is_empty() {
return Ok(self);
}
let mainline_ids: Vec<InstanceId> = {
let mut ids = vec![self.instance_id()];
ids.extend(linebuf.iter().map(|n| n.instance_id()));
ids
};
let pending_reparent: HashSet<RawBytes> =
self.children.iter().map(|(id, _)| id).collect();
Self::prune_destroy_side_branches(
&mut linebuf,
&mainline_ids,
&pending_reparent,
);
self.prune_merge_into_genesis(&mut linebuf);
vsdb_flush();
let kept = self.prune_reparent_children(linebuf.last_mut().unwrap());
vsdb_flush();
self.prune_clear_consumed(&mut linebuf);
let mut genesis = linebuf.pop().unwrap();
genesis.prune_children_exclude(&kept);
Ok(genesis)
}
fn prune_collect_mainline(&self) -> Result<Vec<Self>> {
let p = match self.parent.get_value() {
Some(p) => p,
_ => return Ok(vec![]),
};
let mut seen = HashSet::new();
seen.insert(self.instance_id());
let mut linebuf = vec![p];
loop {
let current_id = linebuf.last().unwrap().instance_id();
if !seen.insert(current_id) {
return Err(VsdbError::Other {
detail: "DAG mainline contains a parent cycle".to_owned(),
});
}
match linebuf.last().unwrap().parent.get_value() {
Some(p) => linebuf.push(p),
None => break,
}
}
Ok(linebuf)
}
fn prune_destroy_side_branches(
linebuf: &mut [Self],
mainline_ids: &[InstanceId],
pending_reparent: &HashSet<RawBytes>,
) {
for node in linebuf.iter_mut() {
let node_id = node.instance_id();
let doomed: Vec<_> = node
.children
.iter()
.filter(|(id, child)| {
!mainline_ids.contains(&child.instance_id())
&& !pending_reparent.contains(id)
})
.collect();
for (id, mut child) in doomed {
if Self::owned_or_residue(node_id, &child) {
child.destroy();
}
node.children.remove(&id);
}
}
}
fn owned_or_residue(owner_id: InstanceId, child: &Self) -> bool {
match child.parent.get_value() {
None => true,
Some(p) => p.instance_id() == owner_id,
}
}
fn prune_merge_into_genesis(&self, linebuf: &mut [Self]) {
let mid = linebuf.len() - 1;
let (others, genesis) = linebuf.split_at_mut(mid);
let genesis = &mut genesis[0];
for i in others.iter().rev() {
Self::prune_fold_node(genesis, i);
}
Self::prune_fold_node(genesis, self);
}
fn prune_fold_node(genesis: &mut Self, src: &Self) {
for (k, v) in src.data.iter() {
if v.is_empty() {
genesis.data.remove(&k);
} else {
genesis.data.insert(k, v);
}
}
}
fn prune_reparent_children(&mut self, genesis: &mut Self) -> Vec<RawBytes> {
let mut kept = vec![];
for (id, mut child) in self.children.iter_mut() {
*child.parent.get_mut() = Some(unsafe { genesis.shadow() });
genesis.children.insert(&id, &child);
kept.push(id);
}
kept
}
fn prune_clear_consumed(&mut self, linebuf: &mut [Self]) {
let mid = linebuf.len() - 1;
let others = &mut linebuf[..mid];
*self.parent.get_mut() = None;
self.children.clear();
self.data.clear();
for i in others.iter_mut() {
*i.parent.get_mut() = None;
i.children.clear();
i.data.clear();
}
}
#[inline(always)]
pub fn prune_children_include(&mut self, include_targets: &[impl AsRef<DagMapId>]) {
self.prune_children(include_targets, false);
}
#[inline(always)]
pub fn prune_children_exclude(&mut self, exclude_targets: &[impl AsRef<DagMapId>]) {
self.prune_children(exclude_targets, true);
}
fn prune_children(&mut self, targets: &[impl AsRef<DagMapId>], exclude_mode: bool) {
let self_id = self.instance_id();
let targets = targets.iter().map(|i| i.as_ref()).collect::<HashSet<_>>();
let dropped_children = if exclude_mode {
self.children
.iter()
.filter(|(id, _)| !targets.contains(&id.as_slice()))
.collect::<Vec<_>>()
} else {
self.children
.iter()
.filter(|(id, _)| targets.contains(&id.as_slice()))
.collect::<Vec<_>>()
};
for (id, _) in dropped_children.iter() {
self.children.remove(id);
}
for (_, mut child) in dropped_children.into_iter() {
if Self::owned_or_residue(self_id, &child) {
child.destroy();
}
}
}
#[inline(always)]
pub fn destroy(&mut self) {
let self_id = self.instance_id();
if let Some(mut parent) = self.parent.get_value() {
let child_ids = parent
.children
.iter()
.filter_map(|(id, child)| (child.instance_id() == self_id).then_some(id))
.collect::<Vec<_>>();
for id in child_ids {
parent.children.remove(id);
}
}
*self.parent.get_mut() = None;
self.data.clear();
let mut seen = HashSet::new();
seen.insert(self_id);
let mut stack = self
.children
.iter()
.map(|(_, c)| (self_id, c))
.collect::<Vec<_>>();
self.children.clear();
while let Some((owner_id, mut node)) = stack.pop() {
if !seen.insert(node.instance_id()) {
continue;
}
if !Self::owned_or_residue(owner_id, &node) {
continue;
}
let node_id = node.instance_id();
node.data.clear();
stack.extend(node.children.iter().map(|(_, c)| (node_id, c)));
node.children.clear();
*node.parent.get_mut() = None;
}
}
#[inline(always)]
pub fn is_the_same_instance(&self, other_hdr: &Self) -> bool {
self.data.is_the_same_instance(&other_hdr.data)
}
}
#[derive(Debug)]
pub struct ValueMut<'a> {
value: RawBytes,
inner: mapx_raw::ValueMut<'a>,
dirty: bool,
}
impl Drop for ValueMut<'_> {
fn drop(&mut self) {
if self.dirty {
assert!(
!self.value.is_empty(),
"empty value is a tombstone; call remove() instead"
);
self.inner.clone_from(&self.value);
}
}
}
impl Deref for ValueMut<'_> {
type Target = RawBytes;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl DerefMut for ValueMut<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.dirty = true;
&mut self.value
}
}