use super::*;
use crate::background::{CheckpointAllocationOwner, CheckpointWorkError};
use crate::relational::overflow::CheckpointRelationalOverflow;
#[derive(Debug, Default)]
pub(super) struct CheckpointOverflows {
values: BTreeMap<Sha256Digest, CheckpointRelationalOverflow>,
admitted_nodes: usize,
allocations: CheckpointAllocationOwner,
}
impl std::ops::Deref for CheckpointOverflows {
type Target = BTreeMap<Sha256Digest, CheckpointRelationalOverflow>;
fn deref(&self) -> &Self::Target {
&self.values
}
}
impl CheckpointOverflows {
pub(super) fn insert(
&mut self,
value: CheckpointRelationalOverflow,
work: &CheckpointWorkContext,
) -> Result<Option<CheckpointRelationalOverflow>, AppendTableError> {
let unit = work.start_unit().map_err(work_error)?;
if !self.values.contains_key(&value.reference.digest) {
let keys = self.values.len().checked_add(1).ok_or_else(|| {
work_error(work.record_failure(CheckpointWorkError::Allocation {
bytes: u64::MAX,
reason: "append overflow map cardinality overflows usize".into(),
}))
})?;
let nodes = keys / 4 + 2;
if nodes > self.admitted_nodes {
let bytes = (nodes - self.admitted_nodes)
.checked_mul(crate::cow::checkpoint_tree_node_bytes::<
Sha256Digest,
CheckpointRelationalOverflow,
>())
.ok_or_else(|| {
work_error(work.record_failure(CheckpointWorkError::Allocation {
bytes: u64::MAX,
reason: "append overflow map node capacity overflows usize".into(),
}))
})?;
self.allocations.reserve(bytes, work).map_err(work_error)?;
self.admitted_nodes = nodes;
}
}
let previous = self.values.insert(value.reference.digest, value);
unit.finish();
work.checkpoint().map_err(work_error)?;
Ok(previous)
}
}