pub struct VersionVector { /* private fields */ }Expand description
Per-replica contiguous prefixes for anti-entropy pulls.
get(replica) == n means every sequence 1..=n for that replica is known.
Later records that arrive before earlier records must not advance this
prefix, otherwise since could hide gaps. Sequence zero is acknowledged
independently by zero_replicas; it is not implied by a positive prefix.
The built-in wire codec carries both Self::entries and
Self::zero_replicas. Custom version exchanges must carry both too. A
receiver can rebuild the vector with Self::from_peer_prefixes after
checking application-owned author and zero-acknowledgement budgets, as below;
record payloads are not required.
Legacy prefix-only exchanges cannot acknowledge zeros and will keep receiving
them until upgraded.
These are claims about the sending peer’s log. The caller is responsible for
their truth: neither observe nor since checks possession of record payloads.
Fabricated IDs can acknowledge missing records and cause since to omit them.
Use crate::EventLog::version to derive claims from records actually admitted.
Checked reconstruction validates each positive prefix, then clones both
collections: for r authors and z zero acknowledgements it takes O(r + z)
time and O(r + z) additional space, independently of the claimed sequences.
Bound both collection sizes before reconstruction and enforce transport byte
limits before decoding to bound the input allocation itself.
Zero-valued prefix entries are noncanonical and are rejected by the checked
constructor; only zero_replicas() acknowledges sequence zero.
use safemesh_crdt::{EventLog, VersionVector};
use std::collections::{BTreeMap, BTreeSet};
fn receive(
prefixes: &BTreeMap<u64, u64>, zeros: &BTreeSet<u64>,
author_budget: usize, zero_budget: usize,
) -> Result<VersionVector, &'static str> {
if prefixes.len() > author_budget || zeros.len() > zero_budget {
return Err("peer version exceeds application budget");
}
VersionVector::from_peer_prefixes(prefixes, zeros).map_err(|_| "invalid prefix")
}
let mut peer = EventLog::new();
peer.append(&mut safemesh_crdt::GSet::new(), 7, 42u64).unwrap();
// Carry both collections over the application's transport.
let prefixes = peer.version().entries().clone();
let zeros = peer.version().zero_replicas().clone();
// This example has one publisher and allocates no sequence-zero records.
let received = receive(&prefixes, &zeros, 1, 0).unwrap();
assert_eq!(&received, peer.version());
assert_eq!(peer.since(&received), peer.since(peer.version()));Implementations§
Source§impl VersionVector
impl VersionVector
Sourcepub fn from_wire_bytes_with_limits(
bytes: &[u8],
limits: VersionVectorLimits,
) -> Result<Self, WireError>
pub fn from_wire_bytes_with_limits( bytes: &[u8], limits: VersionVectorLimits, ) -> Result<Self, WireError>
Decode with explicit author and sequence-zero acknowledgement budgets. Claimed entry counts are checked before reading or allocating entries.
Source§impl VersionVector
impl VersionVector
pub fn new() -> Self
Sourcepub fn from_peer_prefixes(
entries: &BTreeMap<u64, u64>,
zero_replicas: &BTreeSet<u64>,
) -> Result<Self, VersionVectorError>
pub fn from_peer_prefixes( entries: &BTreeMap<u64, u64>, zero_replicas: &BTreeSet<u64>, ) -> Result<Self, VersionVectorError>
Reconstruct a vector from a peer’s canonical positive prefixes and independent sequence-zero acknowledgements.
Accepts every positive u64 prefix, including u64::MAX, without
iterating over sequences. Zero remains noncanonical: use zero_replicas.
This method imposes no collection budget. Use
Self::from_peer_prefixes_with_limits to enforce author and
zero-acknowledgement budgets before validation or cloning.
Callers must retain three application-owned input limits:
- author count bounds prefix validation and map cloning;
- zero-acknowledgement count bounds set cloning;
- encoded byte size, enforced before decoding, bounds input allocation and parsing (including duplicate entries before collection deduplication).
The built-in wire decoder has default entry ceilings; callers can choose their own limits. This constructor imposes no universal application budget. Reconstruction takes O(entries.len() + zero_replicas.len()) time and space.
Sourcepub fn from_peer_prefixes_with_limits(
entries: &BTreeMap<u64, u64>,
zero_replicas: &BTreeSet<u64>,
limits: VersionVectorLimits,
) -> Result<Self, VersionVectorLimitError>
pub fn from_peer_prefixes_with_limits( entries: &BTreeMap<u64, u64>, zero_replicas: &BTreeSet<u64>, limits: VersionVectorLimits, ) -> Result<Self, VersionVectorLimitError>
Reconstruct a peer version with caller-supplied collection budgets.
Checks author count first, then zero-acknowledgement count, before
validating prefixes or cloning either collection. If both budgets are
exceeded, returns VersionVectorLimitError::AuthorLimitExceeded.
No partial vector is returned. Exact limits are accepted.
VersionVectorLimits::default preserves the unbounded constructor’s
values and wraps its errors in VersionVectorLimitError::Prefix.
These checks do not bound decoding or input allocation: callers must
enforce encoded-byte and entry budgets at their decoding boundary too.
pub fn get(&self, replica: u64) -> u64
Sourcepub fn observe(&mut self, id: RecordId)
pub fn observe(&mut self, id: RecordId)
Advance this prefix only when id is the next contiguous sequence.
A missing sequence keeps later records outside the prefix until it arrives.
Use EventLog to ingest out-of-order records; the log remembers gaps
and advances this vector once the prefix is complete.
Sourcepub fn includes(&self, id: RecordId) -> bool
pub fn includes(&self, id: RecordId) -> bool
Return true for an acknowledged zero or a sequence in the writer’s contiguous prefix.
Sourcepub fn entries(&self) -> &BTreeMap<u64, u64>
pub fn entries(&self) -> &BTreeMap<u64, u64>
Positive contiguous prefixes only; does not describe zero possession.
Sourcepub fn zero_replicas(&self) -> &BTreeSet<u64>
pub fn zero_replicas(&self) -> &BTreeSet<u64>
Authors whose sequence-zero record has been observed.
Trait Implementations§
Source§impl Clone for VersionVector
impl Clone for VersionVector
Source§fn clone(&self) -> VersionVector
fn clone(&self) -> VersionVector
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for VersionVector
impl Debug for VersionVector
Source§impl Default for VersionVector
impl Default for VersionVector
Source§fn default() -> VersionVector
fn default() -> VersionVector
Source§impl PartialEq for VersionVector
impl PartialEq for VersionVector
Source§fn eq(&self, other: &VersionVector) -> bool
fn eq(&self, other: &VersionVector) -> bool
self and other values to be equal, and is used by ==.1.0.0 · Source§fn ne(&self, other: &Rhs) -> bool
fn ne(&self, other: &Rhs) -> bool
!=. The default implementation is almost always sufficient,
and should not be overridden without very good reason.Source§impl WireDecode for VersionVector
impl WireDecode for VersionVector
fn decode_wire(cursor: &mut WireCursor<'_>) -> Result<Self, WireError>
Source§fn decode_wire_with_collection_limits(
cursor: &mut WireCursor<'_>,
_limits: CollectionLimits,
) -> Result<Self, WireError>
fn decode_wire_with_collection_limits( cursor: &mut WireCursor<'_>, _limits: CollectionLimits, ) -> Result<Self, WireError>
Source§fn decode_wire_with_limits(
cursor: &mut WireCursor<'_>,
collections: CollectionLimits,
_max_records: Option<usize>,
) -> Result<Self, WireError>
fn decode_wire_with_limits( cursor: &mut WireCursor<'_>, collections: CollectionLimits, _max_records: Option<usize>, ) -> Result<Self, WireError>
Source§fn from_wire_bytes_with_collection_limits(
bytes: &[u8],
limits: CollectionLimits,
) -> Result<Self, WireError>
fn from_wire_bytes_with_collection_limits( bytes: &[u8], limits: CollectionLimits, ) -> Result<Self, WireError>
fn from_wire_bytes(bytes: &[u8]) -> Result<Self, WireError>
Source§impl WireEncode for VersionVector
impl WireEncode for VersionVector
fn encode_wire(&self, out: &mut Vec<u8>) -> Result<(), WireError>
fn to_wire_bytes(&self) -> Result<Vec<u8>, WireError>
Source§impl WireSchema for VersionVector
impl WireSchema for VersionVector
const REQUIRES_ARITY: bool = false
Source§fn wire_schema() -> Cow<'static, [u8]>
fn wire_schema() -> Cow<'static, [u8]>
impl Eq for VersionVector
impl StructuralPartialEq for VersionVector
Auto Trait Implementations§
impl Freeze for VersionVector
impl RefUnwindSafe for VersionVector
impl Send for VersionVector
impl Sync for VersionVector
impl Unpin for VersionVector
impl UnsafeUnpin for VersionVector
impl UnwindSafe for VersionVector
Blanket Implementations§
Source§impl<T> Any for Twhere
T: 'static + ?Sized,
impl<T> Any for Twhere
T: 'static + ?Sized,
Source§fn type_id(&self) -> TypeId
fn type_id(&self) -> TypeId
TypeId of self. Read moreSource§impl<T> Borrow<T> for Twhere
T: ?Sized,
impl<T> Borrow<T> for Twhere
T: ?Sized,
Source§fn borrow(&self) -> &T
fn borrow(&self) -> &T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§unsafe fn clone_to_uninit(&self, dest: *mut u8)
unsafe fn clone_to_uninit(&self, dest: *mut u8)
clone_to_uninit)self to dest. Read moreSource§impl<T, U> Into<U> for Twhere
U: From<T>,
impl<T, U> Into<U> for Twhere
U: From<T>,
Source§fn into(self) -> U
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of
From<T> for U chooses to do.