Skip to main content

laminar_core/checkpoint/
attempt.rs

1//! Identity and ordering for checkpoint attempts.
2
3/// Exact identity of one checkpoint attempt.
4#[derive(
5    Debug,
6    Clone,
7    Copy,
8    PartialEq,
9    Eq,
10    Hash,
11    serde::Serialize,
12    serde::Deserialize,
13    rkyv::Archive,
14    rkyv::Serialize,
15    rkyv::Deserialize,
16)]
17pub struct CheckpointAttempt {
18    /// Logical pipeline epoch represented by this checkpoint.
19    pub epoch: u64,
20    /// Never-reused checkpoint ID within the deployment.
21    pub checkpoint_id: u64,
22}
23
24/// Relation between two checkpoint attempts.
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum CheckpointAttemptRelation {
27    /// Both fields are identical.
28    Exact,
29    /// Both fields are lower than the compared attempt.
30    Older,
31    /// Both fields are higher than the compared attempt.
32    Newer,
33    /// The fields do not define a consistent order.
34    Conflict,
35}
36
37impl CheckpointAttempt {
38    /// Construct an exact checkpoint identity.
39    #[must_use]
40    pub const fn new(epoch: u64, checkpoint_id: u64) -> Self {
41        Self {
42            epoch,
43            checkpoint_id,
44        }
45    }
46
47    /// Construct an attempt in the single durable checkpoint order.
48    #[must_use]
49    pub const fn canonical(checkpoint_id: u64) -> Self {
50        Self::new(checkpoint_id, checkpoint_id)
51    }
52
53    /// Whether both fields represent the same nonzero durable identity.
54    #[must_use]
55    pub const fn is_canonical(self) -> bool {
56        self.epoch != 0 && self.epoch == self.checkpoint_id
57    }
58
59    /// Relate this attempt to `other` without inventing a lexicographic order.
60    #[must_use]
61    pub const fn relation_to(self, other: Self) -> CheckpointAttemptRelation {
62        if self.epoch == other.epoch && self.checkpoint_id == other.checkpoint_id {
63            CheckpointAttemptRelation::Exact
64        } else if self.epoch < other.epoch && self.checkpoint_id < other.checkpoint_id {
65            CheckpointAttemptRelation::Older
66        } else if self.epoch > other.epoch && self.checkpoint_id > other.checkpoint_id {
67            CheckpointAttemptRelation::Newer
68        } else {
69            CheckpointAttemptRelation::Conflict
70        }
71    }
72}