use std::sync::Arc;
use crate::api::errors::Result;
use crate::layout::{frame_created_epoch, BlobGuid, BlobNode, NodeType};
use crate::store::{BlobWriteGuard, BufferManager, CachedBlob};
use super::fresh_blob_guid;
use super::readers::ntype_of;
use super::writers::repoint_blob_node;
pub(super) fn child_is_snapshot_shared(bm: &BufferManager, child: &CachedBlob) -> bool {
let barrier = bm.fork_barrier();
barrier != 0 && {
let probe = child.read();
frame_created_epoch(probe.as_slice()) <= barrier
}
}
pub(super) fn fork_child_if_shared(
bm: &BufferManager,
parent: &mut BlobWriteGuard<'_>,
child_guid: BlobGuid,
child_bytes: &[u8],
parent_off: u32,
) -> Result<Option<(BlobGuid, Arc<CachedBlob>)>> {
let barrier = bm.fork_barrier();
let child_epoch = frame_created_epoch(child_bytes);
if barrier == 0 || child_epoch > barrier {
return Ok(None);
}
{
let frame = parent.frame();
if ntype_of(frame.as_ref(), parent_off)? != NodeType::Blob {
return Err(crate::api::errors::Error::node_corrupt(
"COW parent edge is not a BlobNode",
));
}
let body = frame.body_at_offset(parent_off).ok_or_else(|| {
crate::api::errors::Error::node_corrupt("COW parent edge body missing")
})?;
let edge = *super::cast::<BlobNode>(body);
if edge.child_blob_guid != child_guid {
return Err(crate::api::errors::Error::node_corrupt(
"COW parent edge child identity changed",
));
}
}
let parent_guid = {
let frame = parent.frame();
frame.header().blob_guid
};
let fork_guid = fresh_blob_guid();
let fork_pin = bm.fork_frame(child_bytes, fork_guid, crate::store::STRUCTURAL_SEQ)?;
{
let mut frame = parent.frame();
repoint_blob_node(&mut frame, parent_off, fork_guid)?;
}
bm.stage_cow_reclaim(parent_guid, child_guid, child_epoch);
Ok(Some((fork_guid, fork_pin)))
}