///|
pub(all) suberror ReconcileError {
InvalidConfig(String)
Incompatible(String)
InvalidFrame(String)
LimitExceeded(String)
StaleSnapshot
VerificationFailed
InvalidPlan(String)
} derive(Eq, Debug)
///|
/// Three disjoint hash bands, each of `width` cells. Immutable configuration.
pub struct Config {
priv width : Int32
priv seed : UInt64
} derive(Eq, Debug)
///|
pub fn Config::new(
width : Int32,
seed~ : UInt64 = 1UL,
) -> Config raise ReconcileError {
if width < 1 || width > 262144 {
raise InvalidConfig("width must be between 1 and 262144")
}
{ width, seed, }
}
///|
pub fn Config::width(self : Config) -> Int32 {
self.width
}
///|
pub fn Config::seed(self : Config) -> UInt64 {
self.seed
}
///|
pub fn Config::cells(self : Config) -> Int32 {
self.width * 3
}
///|
/// Commutative, non-cryptographic set fingerprint. This is not authentication.
pub struct Fingerprint {
priv count : Int32
priv sum : UInt64
priv xor : UInt64
} derive(Eq, Debug)
///|
pub fn Fingerprint::count(self : Fingerprint) -> Int32 {
self.count
}
///|
struct Cell {
mut count : Int32
mut key : UInt64
mut check : UInt64
} derive(Debug)
///|
/// Mutable algebraic sketch. Insertion/removal require valid set semantics.
/// Prefer Inventory when callers cannot guarantee uniqueness.
pub struct Sketch {
priv config : Config
priv cells : Array[Cell]
}
///|
/// Decode may be partial; only a complete result is a usable synchronization plan.
pub struct DecodeReport {
priv positive : Array[UInt64]
priv negative : Array[UInt64]
priv residual : Int32
priv steps : Int32
}
///|
pub fn DecodeReport::complete(self : DecodeReport) -> Bool {
self.residual == 0
}
///|
pub fn DecodeReport::positive(self : DecodeReport) -> Array[UInt64] {
self.positive.copy()
}
///|
pub fn DecodeReport::negative(self : DecodeReport) -> Array[UInt64] {
self.negative.copy()
}
///|
pub fn DecodeReport::residual_cells(self : DecodeReport) -> Int32 {
self.residual
}
///|
pub fn DecodeReport::steps(self : DecodeReport) -> Int32 {
self.steps
}
///|
/// Scope separates datasets; epoch identifies an immutable snapshot version.
pub struct Snapshot {
priv scope : UInt64
priv epoch : UInt64
priv fingerprint : Fingerprint
priv sketch : Sketch
}
///|
pub fn Snapshot::scope(self : Snapshot) -> UInt64 {
self.scope
}
///|
pub fn Snapshot::epoch(self : Snapshot) -> UInt64 {
self.epoch
}
///|
pub fn Snapshot::fingerprint(self : Snapshot) -> Fingerprint {
self.fingerprint
}
///|
pub fn Snapshot::config(self : Snapshot) -> Config {
self.sketch.config
}
///|
/// Private fields prevent unvalidated plans being constructed by consumers.
pub struct Plan {
priv scope : UInt64
priv source_epoch : UInt64
priv target_epoch : UInt64
priv source : Fingerprint
priv target : Fingerprint
priv add : Array[UInt64]
priv remove : Array[UInt64]
}
///|
pub fn Plan::additions(self : Plan) -> Array[UInt64] {
self.add.copy()
}
///|
pub fn Plan::removals(self : Plan) -> Array[UInt64] {
self.remove.copy()
}
///|
pub fn Plan::target_epoch(self : Plan) -> UInt64 {
self.target_epoch
}
///|
pub enum Outcome {
Ready(Plan)
Retry(Config)
FullTransfer(Int32)
}
///|
pub struct Policy {
priv max_width : Int32
priv max_differences : Int32
}
///|
pub fn Policy::new(
max_width~ : Int32 = 65536,
max_differences~ : Int32 = 100000,
) -> Policy raise ReconcileError {
if max_width < 1 ||
max_width > 262144 ||
max_differences < 0 ||
max_differences > 1000000 {
raise InvalidConfig("invalid retry or difference budget")
}
{ max_width, max_differences, }
}