mod codec;
mod merge;
mod prepare;
mod range;
mod read;
use crate::property_graph::{NodeId, RelId, catalog::RelTypeId};
pub use codec::{encode_base, encode_delta};
#[cfg(any(test, feature = "test-seams"))]
pub(crate) use merge::exact_split_fixture;
pub use merge::{MERGE_STATE_BYTES, Merged, Partition, merge};
#[cfg(any(test, feature = "test-seams"))]
pub(crate) use prepare::QUALIFICATION_RANGES;
pub(crate) use prepare::relocate_ranges;
pub use prepare::{NativeGraphBase, NativeGraphCandidate, prepare_native_graph};
pub(crate) use range::validate_descriptor;
pub use range::{
RANGE_DESCRIPTOR_BYTES, RangeDescriptor, RangeEditContext, RangeScratch, ValidatedRange,
put_range, remove_range, validate_range,
};
pub(crate) use read::ExpansionResume;
pub use read::{
AdjacencyQuery, AdjacencyRow, NativeGraphReader, RelationshipRange, RelationshipRow,
};
pub const HEADER_BYTES: usize = 96;
pub const MAX_BASE_ENTRIES: usize = 4096;
pub const MAX_DELTA_RUNS: usize = 8;
pub const MAX_PENDING_ENTRIES: usize = 2048;
pub const MAX_MERGED_ENTRIES: usize = MAX_BASE_ENTRIES + MAX_PENDING_ENTRIES;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum Direction {
Out = 1,
In = 2,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum UpperBound {
Exclusive(RelId),
Infinity,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RangeKey {
pub node: NodeId,
pub rel_type: RelTypeId,
pub direction: Direction,
pub lower: RelId,
pub upper: UpperBound,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Edge {
pub rel: RelId,
pub neighbor: NodeId,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum Action {
Insert = 1,
Delete = 2,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct DeltaEntry {
pub edge: Edge,
pub action: Action,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FormatIssue {
Tag,
Reserved,
Length,
Identity,
Range,
Order,
Group,
Sequence,
SequenceConflict,
Neighbor,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LimitIssue {
BaseEntries,
DeltaRuns,
PendingEntries,
Output,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Error<E> {
Format(FormatIssue),
Limit(LimitIssue),
Control(E),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Work {
HeaderBytes(usize),
MergeRun,
EntryBytes(usize),
Compare,
CopyBytes(usize),
Finish,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Admission {
NoChange,
Append,
ConsolidateFirst,
}
pub fn append_admission(
existing_runs: usize,
pending_entries: usize,
incoming_entries: usize,
) -> Result<Admission, LimitIssue> {
if existing_runs > MAX_DELTA_RUNS {
return Err(LimitIssue::DeltaRuns);
}
if pending_entries > MAX_PENDING_ENTRIES || incoming_entries > MAX_PENDING_ENTRIES {
return Err(LimitIssue::PendingEntries);
}
if incoming_entries == 0 {
return Ok(Admission::NoChange);
}
if existing_runs == MAX_DELTA_RUNS || pending_entries + incoming_entries > MAX_PENDING_ENTRIES {
Ok(Admission::ConsolidateFirst)
} else {
Ok(Admission::Append)
}
}
fn step<E>(c: &mut (impl FnMut(Work) -> Result<(), E> + ?Sized), w: Work) -> Result<(), Error<E>> {
c(w).map_err(Error::Control)
}
fn compare<T: Ord, E>(
left: T,
right: T,
c: &mut impl FnMut(Work) -> Result<(), E>,
) -> Result<std::cmp::Ordering, Error<E>> {
step(c, Work::Compare)?;
Ok(left.cmp(&right))
}
fn valid_range<E>(key: RangeKey) -> Result<(), Error<E>> {
if let UpperBound::Exclusive(upper) = key.upper
&& key.lower >= upper
{
return Err(Error::Format(FormatIssue::Range));
}
Ok(())
}
fn valid_edge<E>(
key: RangeKey,
edge: Edge,
previous: Option<RelId>,
c: &mut impl FnMut(Work) -> Result<(), E>,
) -> Result<(), Error<E>> {
use std::cmp::Ordering;
if let Some(previous) = previous
&& compare(previous, edge.rel, c)? != Ordering::Less
{
return Err(Error::Format(FormatIssue::Order));
}
if compare(edge.rel, key.lower, c)? == Ordering::Less {
return Err(Error::Format(FormatIssue::Range));
}
if let UpperBound::Exclusive(upper) = key.upper
&& compare(edge.rel, upper, c)? != Ordering::Less
{
return Err(Error::Format(FormatIssue::Range));
}
Ok(())
}
#[cfg(all(test, feature = "allocation-audit"))]
mod tests;