Skip to main content

dynomite/embed/
snapshots.rs

1//! Owned point-in-time topology snapshots.
2//!
3//! Each type is `Clone` and free of internal locks so it can be
4//! held across an `await` without blocking the runtime.
5
6use crate::cluster::peer::{Peer, PeerEndpoint, PeerState};
7use crate::cluster::Datacenter;
8use crate::hashkit::DynToken;
9
10/// Owned snapshot of one peer in the cluster ring.
11///
12/// # Examples
13///
14/// ```
15/// use dynomite::embed::PeerSnapshot;
16/// use dynomite::cluster::peer::{Peer, PeerEndpoint, PeerState};
17/// use dynomite::hashkit::DynToken;
18/// let p = Peer::new(
19///     0, PeerEndpoint::tcp("h".into(), 1), "r".into(), "d".into(),
20///     vec![DynToken::from_u32(0)], true, true, false,
21/// );
22/// let snap = PeerSnapshot::from(&p);
23/// assert_eq!(snap.idx, 0);
24/// ```
25#[derive(Clone, Debug, Eq, PartialEq)]
26pub struct PeerSnapshot {
27    /// Index of the peer in the pool's peer array.
28    pub idx: u32,
29    /// Hostname or IP.
30    pub host: String,
31    /// TCP port.
32    pub port: u16,
33    /// Datacenter name.
34    pub dc: String,
35    /// Rack name.
36    pub rack: String,
37    /// Lifecycle state.
38    pub state: PeerState,
39    /// Token list at snapshot time.
40    pub tokens: Vec<DynToken>,
41    /// True for the local node.
42    pub is_local: bool,
43}
44
45impl From<&Peer> for PeerSnapshot {
46    fn from(p: &Peer) -> Self {
47        Self {
48            idx: p.idx(),
49            host: p.endpoint().host().to_string(),
50            port: p.endpoint().port(),
51            dc: p.dc().to_string(),
52            rack: p.rack().to_string(),
53            state: p.state(),
54            tokens: p.tokens().to_vec(),
55            is_local: p.is_local(),
56        }
57    }
58}
59
60impl PeerSnapshot {
61    /// Convert back to a runtime [`Peer`] (used by tests and
62    /// by the embed-internal forwarder).
63    #[must_use]
64    pub fn to_peer(&self) -> Peer {
65        Peer::new(
66            self.idx,
67            PeerEndpoint::tcp(self.host.clone(), self.port),
68            self.rack.clone(),
69            self.dc.clone(),
70            self.tokens.clone(),
71            self.is_local,
72            true,
73            false,
74        )
75    }
76}
77
78/// Owned snapshot of one rack in a datacenter.
79#[derive(Clone, Debug, Eq, PartialEq)]
80pub struct RackSnapshot {
81    /// Rack name.
82    pub name: String,
83    /// Continuum size.
84    pub continuum_len: usize,
85}
86
87/// Owned snapshot of one datacenter and its racks.
88#[derive(Clone, Debug, Eq, PartialEq)]
89pub struct DatacenterSnapshot {
90    /// DC name.
91    pub name: String,
92    /// Racks in this DC.
93    pub racks: Vec<RackSnapshot>,
94}
95
96impl From<&Datacenter> for DatacenterSnapshot {
97    fn from(dc: &Datacenter) -> Self {
98        Self {
99            name: dc.name().to_string(),
100            racks: dc
101                .racks()
102                .iter()
103                .map(|r| RackSnapshot {
104                    name: r.name().to_string(),
105                    continuum_len: r.continuums().len(),
106                })
107                .collect(),
108        }
109    }
110}
111
112/// Owned snapshot of the token ring.
113///
114/// Each entry is a `(token, owner_peer_idx)` pair.
115#[derive(Clone, Debug, Default, Eq, PartialEq)]
116pub struct RingSnapshot {
117    /// Token-to-owner pairs in token order.
118    pub entries: Vec<(DynToken, u32)>,
119    /// Monotonic generation counter.
120    pub generation: u64,
121}